Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion content/docs/(overview)/devices.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ An app built on the [Swift SDK](/swift-sdk) is a device, and so is the [CLI](/cl

A device chooses the **slice** of the instance it keeps: a list of types, a tier, and the edge types it holds. For example, every `core.note` and `core.task` in the library. It fills its copy once by reading every item in the slice, then keeps it current from the instance's [event stream](/events). To hold every type except `system.*`, declare `*` alone: the device reads the whole slice in one pass, with no need to read the catalog and name its types first. `*` beside `system.*` types adds them, and `*` beside any other type is refused `invalid` before anything is read.

Reads come from the copy, with no connection needed. A file's bytes are there once the device has fetched them. The core also [reads saved views](/guides/read-a-view), including layout order, groups, counts and sums. **A view's item or group read needs the whole query held** and is refused with a reason if the copy cannot answer it completely.
Reads come from the copy, with no connection needed. A file's bytes are there once the device has fetched them. The core also [reads saved views](/guides/read-a-view), including sort order, groups and counts. **A view's item or group read needs the whole query held** and is refused with a reason if the copy cannot answer it completely.

**While a device fills its copy, it answers direct item reads from what has arrived.** A list or search without a saved view returns the items the copy holds so far and marks the answer `partial`; once the copy is whole, the same read is marked `complete`. A read by ID answers for an item that has arrived, and is refused `hydration_incomplete` for one that hasn't. Until the copy is whole, edge reads are refused `hydration_incomplete`, because an edge's two ends can arrive on different pages. A write to an item that has arrived, or a new item, is queued against the version the copy holds and sent once the copy is whole. This includes a file added on its own or attached to an item that has arrived: the device keeps its bytes and uploads them with the rest of the queue. A write to an item that hasn't arrived, or a file attached to one, is refused `hydration_incomplete`, because there is no version to base it on, and a drain is refused `hydration_incomplete` until the copy is whole. **Edge writes are refused `hydration_incomplete` until the copy is whole**, because a page still to arrive can bring the instance's edge in place of the one a write was made against. An edit that changes an item's body is still queued, and the device reads the body's links and embeds and makes their edges once the server answers the edit. The device's status reports how many items the fill has brought so far and, where the instance counted them, how many the slice held when the fill began, so an app can show how far the fill has come. Compare those two figures, not the count of items the copy holds, which also includes pinned items and creates that are still queued. The Swift SDK returns these answers as `Rows` with a `completeness`.

Expand Down
2 changes: 1 addition & 1 deletion content/docs/(reference)/api-reference/index.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ The reference groups operations by what they act on. The groups and the operatio
| Event stream | Changes to items and edges, streamed as they happen | [Stream change events](/api-reference/event-stream/streamEvents) |
| Webhooks | Changes sent to a URL you choose, and each delivery's record | [Create a webhook](/api-reference/webhooks/createWebhook) |
| Folders | A folder's settings, held as a `system.folder` item | [Create a folder](/api-reference/folders/createFolder) |
| Views | Saved lists of items and how each app shows them, held as `system.view` items | [Create a view](/api-reference/views/createView) |
| Views | Saved lists of items with their sort and grouping, held as `system.view` items | [Create a view](/api-reference/views/createView) |
| Connectors | Processes outside the server that read and write on your behalf, with their heartbeats and runs | [Register a connector](/api-reference/connectors/registerConnector) |
| Connector state | What the instance keeps for a connector's source: its hold, its state and its agreements | [Take a connector hold](/api-reference/connector-state/takeConnectorHold) |
| Inbound webhooks | Addresses where a service sends requests to a connector, and the deliveries Marfa stores for it | [Create an inbound endpoint](/api-reference/inbound-webhooks/createInboundEndpoint) |
Expand Down
6 changes: 3 additions & 3 deletions content/docs/(reference)/cli.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -232,14 +232,14 @@ That's how the owner makes the first key in the [Quickstart](/quickstart). These

## Read a view from a working copy

The `marfa device views` commands read saved views from the database named by `--db`. **They need no server connection.** [Read a view offline](/guides/read-a-view) shows how to fill the copy and read a layout.
The `marfa device views` commands read saved views from the database named by `--db`. **They need no server connection.** [Read a view offline](/guides/read-a-view) shows how to fill the copy and read its items and groups.

| Command | Answer |
| --- | --- |
| `marfa device views list` | Views held in the copy. |
| `marfa device views get <id>` | One view's settings and version. |
| `marfa device views groups <id> --layout <id>` | A layout's groups, counts and sums; `--time-zone` selects the time zone for date buckets. |
| `marfa device items list --view <id> --layout <id>` | The view's items in layout order; `--limit` and `--offset` select a page. |
| `marfa device views groups <id>` | The view's groups and counts; `--time-zone` selects the time zone for date buckets. |
| `marfa device items list --view <id>` | The view's items in its sort order; `--limit` and `--offset` select a page. |
| `marfa device search <text> --view <id>` | Search matches within the view's query. |

Each command takes `--json`. A view whose whole query or grouping is not held is refused with a reason.
Expand Down
2 changes: 1 addition & 1 deletion content/docs/catalog/(system)/view.mdx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
title: View
description: "A saved list of items, held here and shared by every app: which items, and how each layout shows them. Written only through /views: created, changed at a version, and deleted, which removes it at once with no trash. Lifecycle bounded to active | revoked. Has no tier."
description: "A saved list of items, held here and shared by every app: which items, in what order and how they group. How an app shows them is the app's own. Written only through /views: created, changed at a version, and deleted, which removes it at once with no trash. Lifecycle bounded to active | revoked. Has no tier."
identifier: system.view
---

Expand Down
23 changes: 12 additions & 11 deletions content/docs/guides/list-filter-search.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -231,12 +231,13 @@ The whole window comes in one page, in order of `starts_at`. A window spans at m

## Save a list as a view

A [view](/catalog/view) saves a listing so every app shows the same one: its `query` says which items it lists, and its `layouts` say how each one shows them. [Create a view](/api-reference/views/createView) with a `title`, a `query` of `types`, `tier`, `state`, `filter` and `beneath` that says which items it lists, and at least one layout, each with an `id` and a `kind` (`list`, `table`, `board`, `gallery`, `calendar`, `timeline`, `chart` or `map`):
A [view](/catalog/view) saves a listing so every app shows the same one: its `query` says which items it lists, and its `sort` and `group` say in what order and how they group. **How an app shows the items is the app's own**, so a view holds no layout. [Create a view](/api-reference/views/createView) with a `title`, and optionally a `query` of `types`, `tier`, `state`, `filter` and `beneath`, a `sort` of `by` and `direction` keys, and a `group` with a `by` field:

```bash tab="CLI" tab-group="client"
marfa views create --title "Open tasks" \
--query '{"types":["core.task"],"filter":"properties.status neq \"completed\""}' \
--layouts '[{"id":"main","kind":"board","group":{"by":"properties.priority"}}]'
--sort '[{"by":"updated_at","direction":"desc"}]' \
--group '{"by":"properties.priority"}'
```

```http tab="HTTP"
Expand All @@ -247,9 +248,8 @@ Content-Type: application/json
{
"title": "Open tasks",
"query": { "types": ["core.task"], "filter": "properties.status neq \"completed\"" },
"layouts": [
{ "id": "main", "kind": "board", "group": { "by": "properties.priority" } }
]
"sort": [{ "by": "updated_at", "direction": "desc" }],
"group": { "by": "properties.priority" }
}
```

Expand All @@ -258,20 +258,21 @@ const { data } = await marfa.POST("/views", {
body: {
title: "Open tasks",
query: { types: ["core.task"], filter: 'properties.status neq "completed"' },
layouts: [
{ id: "main", kind: "board", group: { by: "properties.priority" } },
],
sort: [{ by: "updated_at", direction: "desc" }],
group: { by: "properties.priority" },
},
});
```

The answer is the view as a `system.view` item at `version` 1. The server returns its settings, not the items it lists. **The device core can read its items and layout groups offline**, as [Read a view offline](/guides/read-a-view) shows. A layout only arranges, so it takes no filter of its own.
The answer is the view as a `system.view` item at `version` 1. The server returns its settings, not the items it lists. **The device core can read its items and groups offline**, as [Read a view offline](/guides/read-a-view) shows.

- **To change a view,** [update it](/api-reference/views/updateView) with the `version` you read and the settings you change. Each one you name is replaced whole, `layouts` included, and a change based on an older version still applies when nobody changed the same setting since.
A view's `filter` takes any expression this guide describes, so a view can list one folder's items with `edge[in-folder] eq "<folder id>"`, or one source's with `source eq "<source>"`.

- **To change a view,** [update it](/api-reference/views/updateView) with the `version` you read and the settings you change. Each one you name is replaced whole, and a change based on an older version still applies when nobody changed the same setting since. To stop a view grouping its items, send `group: null`, or run `marfa views change <id> --version <n> --group null`; the change is to the `group` setting alone, so it follows the same rule.
- **To delete a view,** [delete it](/api-reference/views/deleteView). It's gone at once, with no trash.
- **To read a view,** [get it](/api-reference/items/getItem) by its `id`, or list the type `system.view`, like any other item.

Writing a view needs write on `system.view`, and reading one needs read; a `content:*` scope reaches neither. Marfa refuses a malformed setting before it writes anything, and names it in `details.errors[0].path`, such as `layouts.0.group.bucket`. The rules are in the [views](https://github.com/withmarfa/marfa/blob/main/conformance/spec/views.md) chapter of the contract.
Writing a view needs write on `system.view`, and reading one needs read; a `content:*` scope reaches neither. Marfa refuses a malformed setting before it writes anything, and names it in `details.errors[0].path`, such as `group.bucket`. The rules are in the [views](https://github.com/withmarfa/marfa/blob/main/conformance/spec/views.md) chapter of the contract.

## When a query is refused

Expand Down
Loading
Loading