The content as the screens see it
cms.data is the DataClient the content screens run on: the site's model as collections of nodes
with plain values. A plugin that lists or edits content through it gets the same lists, display names
and saving as those screens. It works in the offline demo too, where cms.store is null. For typed
queries, relations, transactions and types that are not collections, use cms.store
(chapter 19).
import { useEffect, useState } from 'react';
import { useCms, type CmsApi, type NodeData } from '@relatude/sdk';
/** The ten articles changed last, kept current as editors save. */
function useLatestArticles() {
const cms = useCms();
const [items, setItems] = useState<NodeData[]>([]);
useEffect(() => {
const load = () => void cms.data.query('IArticle', { pageSize: 10 }).then(r => setItems(r.items));
load();
return cms.data.onChange(load); // returns the unsubscribe
}, [cms]);
return items;
}
/** Changes one value: save() writes only what differs from the base. */
async function retitle(cms: CmsApi, id: string, title: string) {
const node = await cms.data.get(id);
if (node) await cms.data.save({ ...node, values: { ...node.values, Title: title } }, node.values);
}DataClient |
Does |
|---|---|
schema(), typeSchema(typeId) |
the collections (the concrete node types of the site's model, without Relatude.DB's own), or one by CodeName |
query(typeId, { search?, page?, pageSize?, sort? }) |
{ items, total }; page counts from 0, 50 to a page; sort is newest (the default), oldest or name |
get(id), nodes(ids) |
one node with its relation ends; several nodes, in the order asked |
refs(ids) |
{ id, type, name } for each id, to show linked nodes by name |
search(text) |
up to eight nodes of any collection |
displayName(node) |
the name lists show |
create(typeId) |
an unsaved draft with the type's default values; its id starts with draft- |
save(node, base?) |
inserts a draft, or writes the values that differ from base; answers the node as stored |
remove(id) |
deletes the node |
onChange(listener) |
content changed, here or by another editor; returns the unsubscribe |
meta(id), metaChoices(), saveMeta(id, changes) |
the node's address, access groups, site, release and expiry; what they can be set to; writing those changes names (null clears one) |
uploadFile(id, property, file, { signal?, onProgress? }) |
puts a file into a file property at once; answers the file as stored |
copyFile(id, property, { node, property }), removeFile(id, property) |
copies another node's file in, on the server; takes the file out |
contentLinks(links), contentLink(id, file?) |
what stored links (#…) in HTML point at; the stored link to a node or its picture |
saveLayout(typeId, layout) |
saves a type's form layout (Form layouts) |
save writes only what differs from base, or else from the node as this client last read it, so it
never overwrites what someone else saved in the meantime. onChange passes the ids of the changed
nodes, or none when anything may have changed. nodes and refs leave out nodes that are gone or
that the user cannot read. The file, link and layout methods are optional in the type: call them as
cms.data.uploadFile?.(…).
A NodeData is { id, type, createdUtc, updatedUtc, values, image? }, plus revision, status
(whether readers see it) and site from the CMS. values are keyed by CodeName:
| Property | Its value |
|---|---|
| a date | ISO 8601 text |
| an enum | its name |
a relation's "one" end, a Reference<T> |
the related node's id |
a relation's "many" end, a References<T> |
the related nodes' ids, in order |
| an embedded list | its inner nodes, { id, type, values, image? } |
| a file | a FileData: { name, size, contentType, width, height, url, thumbnailUrl?, previewUrl?, converting? } |
save never writes files: the file methods write them at once. image is the node's first
thumbnail. While one is still being made, such as a video's frame, imageConverting says which
property and how far along it is, and fileInfo(id, property) asks again.
TypeSchema |
Is |
|---|---|
id |
the CodeName, IArticle |
name |
the model's title ([Node(Title = "…")]), else one made from the CodeName: IArticlePage is "Article page" |
description |
the model's [Node(Description = "…")], shown in the create wizard |
icon |
the node type's icon as SVG ([Node(Icon = "…")], else the closest base type's), else an icon name guessed from the type's name |
properties |
the editable properties: id (the CodeName), name, type (the editor type), required, declaredBy, defaultValue and more |
inherits |
the base types, nearest first |
nameProperty |
the property that names the node, shown above the form's tabs |
Title, description and icon can also be set in the Relatude.DB admin UI. Draw the icon with
<Icon name={type.icon} />, which takes an icon name or SVG source.