Pages

A page is a markdown document that shows records from your collections: a table of orders, one customer’s record, how many leads came in. You write it on Pages in the console, preview it as you type, and publish it. A page is a record published like a loop: you edit a draft, and readers see the published version until you publish the next one.

Members and admins read pages in the console, and a published page can also be placed on your own site in a frame (see Put a page on your site), where a block can hold a loop’s chat or a form a reader adds a record with (see Let readers add a record).

Write a page

  1. Open Pages and press New page.
  2. Under Start from, keep A blank page, or choose one of the starter pages.
  3. Enter a page id, such as order_status. It names the page and never changes: a lower-case letter, then lower-case letters, digits or underscores. A starter fills in its own id until you type one.
  4. Press Write its first draft. The editor opens with the document: a blank page lists your account’s first collection, if it has one; a starter is its document under your id.
  5. Edit the document. The preview beside it follows your typing. Hover a key to read what it means; a key the page does not have, or a value it does not take, is marked as you type.
  6. Press Save draft v1.

A save that does not pass is refused, and your text stays as you typed it. The save checks in two steps. First it checks the document itself, and names every problem there at once, each at its template line or at the key it is about, with the fix. Only when the document passes does it check the blocks against your account, so a second save can find problems that the first did not name.

Ask LoopAssistant for a page

You can also ask LoopAssistant for a page, for example “a page that shows my leads to my team”. LoopAssistant asks who reads the page and what it shows, and then proposes it on a card. The card shows who may read the page, each collection it reads, and what each block shows.

  • Approve saves the page as a draft. Nothing is published yet.
  • Open Pages to read the draft, and publish it there as any other draft.

LoopAssistant proposes pages for members and admins only. A page for visitors is written on the Pages screen.

If LoopAssistant names a collection your account does not have, the card is refused with the collections you do have, and LoopAssistant proposes again with one of them.

Starter pages

Three starter pages show the common shapes. Each one names a collection or a loop: change the name to one your account has.

StarterWho reads itWhat it shows
Members’ pageMembers and adminsHow many records one collection holds, and a table of them.
WaitlistVisitorsA short welcome, and a loop’s chat where a visitor joins your waitlist.
Help centreVisitorsA table of answers from one collection.

Choose one under Start from on New page, then change each name in it to one your account has, and its readers if you want others, before you save and publish. LoopAssistant can also propose the members’ page. Write the waitlist and the help centre on the Pages screen, because a page for visitors needs an identity block in its access, as a loop’s does. Their documents:

The waitlist:

# A starter page: a public page where a visitor joins your waitlist by talking
# to a loop. It assumes a published loop named `waitlist`; name yours.
page_id: waitlist
title: Join the waitlist
access:
  readers: [anonymous]
  identity: {kind: anonymous, limits: {per_ip: 30/1m}}
loops: [waitlist]
template: |
  # Join the waitlist

  Tell us who you are and what you need, and we will let you know when it opens.

  {{loop waitlist}}

The help centre:

# A starter page: public answers from a collection your loops keep. It assumes
# an `articles` collection with `title` and `answer` fields; name yours.
page_id: help_centre
title: Help centre
access:
  readers: [anonymous]
  identity: {kind: anonymous, limits: {per_ip: 30/1m}}
collections:
  - {name: articles, read: [anonymous]}
template: |
  # Help centre

  {{collection articles fields=[title, answer] limit=100}}

The page document

page_id: order_status
title: Order status
access:
  readers: [member, admin]
collections:
  - {name: orders, read: [member, admin]}
template: |
  # Order status

  {{count orders}} orders so far. The latest:

  {{collection orders fields=[number, customer, status] limit=20}}
KeyWhat it says
page_idThe page’s id. It must be the id you gave the page.
titleThe title a reader sees in the page list.
accessreaders: who may read the page, any of member and admin.
collectionsEach collection the page’s blocks may show, and who may read it: read: [member, admin]. A block may show only a collection listed here.
collections … rowsOptional. Leave it out, and a reader sees every record of that collection they may read. Write rows: owner_field:<field> to show each reader who is not a member only the records whose <field> holds their own identity. To fill <field> with that identity when a loop writes the record, bind it to run_subject (see Record who started the run). A member or an admin always sees every record.
collections … writeOptional. Who may add a record to that collection through a {{form}} block: any of anonymous, user, member and admin. Leave it out, and nobody can. See Let readers add a record.
templateThe page itself: markdown, with blocks in {{ }}.

A document may also carry delivery and loops. delivery puts the page on your site (see Put a page on your site), and loops lists the loops whose chat a {{loop}} block shows. A console page needs neither.

Blocks

A block is one {{ }} in the template, on one line. It shows records from a collection the page lists, and it sits in the page where you write it.

BlockWhat it shows
{{collection orders}}A table of the collection’s records.
{{record orders A-1042}}One record, by its id: the value of the collection’s key field.
{{count orders}}How many records the collection holds. Above 500 it reads “500 or more”.
{{fields orders}}The collection’s declared fields and their types.
{{loop lead_qualification}}The loop’s chat, on a page placed on your site. It runs as the page’s reader, so they sign in once. The loop must be published, listed under the page’s loops, and sign readers in the same way as the page: a save or a publish is refused when it signs them in another way. To let the chat change what its reader sees on the page, for their visit (write in a scratchpad, filter or refresh a table, or scroll to a block), give the loop client_navigate in its capabilities; its entry may name the tools, page_write, page_filter, page_refresh, page_focus and page_prefill. page_filter narrows a table by a field’s value, by a number range on a field that holds numbers (at_least, at_most), or by both on different fields, and the table says what it shows (“Showing 2 of 3 records where price is at most 55”). Nothing it does changes a record, and another reader of the page sees it unchanged. After each reply, the page reads its blocks again, so a table shows a record the chat just saved without a reload. The console’s preview says where the chat will show.
{{form waitlist fields=[email, company]}}A form that adds one record to the collection, with one input per listed field, checked against the field’s declared type. A reader may use it only if the page’s collections entry names them in write; an anonymous visitor also within the page’s per-address limit and its monthly cap. A form only adds: it never changes a saved record. After a save, the page’s blocks that show the collection update. The console’s preview shows the form and does not save.
{{scratchpad answer}}Nothing, until a {{loop}} block’s chat writes into it for its reader: the loop’s answer laid out on the page, at most 4,000 characters, until the reader leaves.

A collection block takes three keys, and a record block takes fields=:

KeyWhat it does
fields=[number, status]The columns to show, in this order. Without it, the block shows every declared field. Each column is headed by its field in words: pickup_date reads “Pickup date”.
limit=20The most rows to show, from 1 to 100. The default is 100.
view=tableThe only view today, and the default.

A table cell shows at most 160 characters of a value. Every value is shown as text, never as markup.

The second step checks each block against your account. A block that names a collection no loop declares or writes is refused with the collections you have. A field the collection does not declare is refused with the fields it has. A collection that only a pipeline step writes declares no fields, so its field names are not checked.

Preview as a reader

The preview shows the page as one reader sees it. Read as offers the page’s own readers, for example an anonymous visitor on a page for visitors, and opens on the widest of them: anonymous visitors, then verified users, members and admins. A block whose collection does not grant that reader shows why in its place, and names the fix: add the reader to that collection’s read. The rest of the page still shows.

A block that cannot show for any other reason also says why in its place: a record id the collection does not hold, or a collection no loop writes any more.

Publish

Press Publish v1…. The publish card shows what the server read from your draft, before anything is published:

  • who may read the page,
  • each collection it may read, and who reads it,
  • one sentence for each block: what it shows, and for whom,
  • what it warns about but does not refuse: an embedded loop with nothing published, whose chat shows nothing yet, and one that cannot change the page because its capabilities omit client_navigate.

The card also shows the document itself. Press Publish v1 to publish. Publishing approves the document as it stands, and the published record is what readers see. A published version is never written again.

If the draft is saved again while the card is open, the publish is refused: review it again.

Put a page on your site

A page reaches readers outside the console when its document says who they are and where the page may be framed:

access:
  readers: [anonymous]
  identity: {kind: anonymous, limits: {per_ip: 30/1m}}
delivery:
  kinds: [embed]
  origins: [https://shop.example]

Publish it. The page’s screen then shows Put this page on your site: an <iframe> to paste into a page of a site under origins, and Copy. Accent colour sets the frame’s buttons and links for that snippet, checked as for a chat (your own accent colour). On any other site the frame says it is not set up for that site; add the site to origins and publish again. If the page declares embed with no origins, the screen says so instead of giving code that cannot work.

If the page’s readers are your own signed-in users (readers: [user] with an identity of kind signed_assertion or oidc), the frame asks your page who the reader is. The screen shows the few lines your page adds to answer it: a fresh assertion signed with the page’s secret, or the reader’s id token from your sign-in provider, each time it asks. The page’s signing secret is on the same screen, for an owner.

While the frame waits for your page’s answer, the reader sees “Signing you in…”. If your page never answers (those lines are missing, or the page is for members and admins only), the frame adds after ten seconds that the page is for signed-in readers and the site has not signed them in. It keeps waiting, so a late answer still opens the page. The browser’s console carries the page door’s own sentence, for you.

Give a page its own address

A page can also have an address of its own on plutonium.io, for anybody who has the link. Set public_path: true under delivery, and let anonymous readers read it:

access:
  readers: [anonymous]
  identity: {kind: anonymous, limits: {per_ip: 30/1m}}
delivery:
  kinds: [embed]
  origins: [https://shop.example]
  public_path: true

Publish it. The page is then at https://plutonium.io/p/<public id>, where the public id is the pg_… id on the page’s screen. A visitor gets the published version as an ordinary web page: it runs no script, so it reads the same with scripts turned off, and each table shows only what the page’s collections let an anonymous reader see.

The address shows nothing that is not public. If the page does not set public_path: true, or its readers do not include anonymous, a visitor reads “This page is not public.” An address that names no page reads “There is no page at this address.” A visitor’s network that asks too often reads “Too many requests from your network. Try again in a minute.”

Let readers add a record

A {{form}} block lets a reader add a record to a collection, such as a visitor joining a waitlist. Name the reader in the collection’s write, and list the fields the form asks for:

access:
  readers: [anonymous]
  identity: {kind: anonymous, limits: {per_ip: 30/1m, monthly_writes: 1000}}
delivery:
  kinds: [embed]
  origins: [https://shop.example]
collections:
  - {name: waitlist, read: [anonymous], write: [anonymous]}
template: |
  {{form waitlist fields=[email, company]}}

  {{count waitlist}} people are waiting.
  • monthly_writes is the most records anonymous visitors may add through the page’s forms in one calendar month (UTC). A page whose write names anonymous must set it, or its save is refused with that fix. Past it, a visitor reads that the page has taken all the saves its owner allows this month, and when it takes more.
  • Each value is checked against the field’s type, and a wrong one is named at its field. The form must include the collection’s key field, which names the record.
  • A form only adds. If a record with the same key is saved already, nothing changes. A reader who may read the collection is told the record exists; anyone else sees the ordinary “saved”, so a form never tells a visitor what somebody else saved.
  • If rows: owner_field:<field> keeps the collection to each reader’s own records, the form fills <field> with the reader’s identity, so the record is theirs.
  • If you publish the page again while a reader has it open, their save is refused and asks them to reload the page.

A form saves in the frame on your site and on the page’s own address (/p/<public id>). On the page’s own address it works with scripts turned off: a save reloads the page, which says above the form whether the record was saved or what to fix. It saves only when sent from that page, never from another site.

Edit a published page

Press Edit as draft v2. Your edit is saved as the next draft, and readers keep the published version until you publish the draft. While a draft is open, the page says so: “Draft v2 is saved and not published. Readers still see v1.”

To throw a draft away, press Discard draft v2…. Readers keep the published version. A page that was never published has nothing else, so discarding its only draft removes the page.

Who may do what

OwnerMember
Write, preview and save a draftYesYes
Publish a draftYesYes
Discard a draftYesYes
Delete a pageYesNo

Delete page… removes every version of the page, and the screen goes back to the list. Only an owner sees it; a member sees that it is the owner’s.