Aller au contenu principal

App data sources

A data source connects an App to a custom table. The same records can appear as cards, a list, a single record, a chart, or a custom Blueprint. A table supplies storage and fields; you choose the interface.

Connect a table​

  1. Open your App in Operations Studio and choose Data in the editor toolbar.
  2. Choose Connect table, select an existing table, and give the source a useful name. You can also create a table here and open its field settings.
  3. Choose the operations this App needs: reading, creating, editing, or deleting records. A new source starts with read access.
  4. Choose whether users see only records they created. This is enabled initially. Shop-floor accounts always work with their own records.

Sources belong to the App and can be reused across tabs and Blueprints. Changing or removing a connection affects the next published App version. Disconnecting a source keeps the table and its records.

Choose how records appear​

In a new React App, author the cards, list, selected-record details or chart in source. Use the named data-source SDK below to read and write records; displaying a control does not grant the corresponding operation. Ask Konnie for the actual columns, filters, pagination and empty/error states the task needs.

Existing component-based Apps may offer a Data view with Cards, List, Single record or Chart and configured Add/Edit/Delete controls. Those views use the same source permissions and typed schema. Their existing configuration is a compatibility path; new Apps can own the complete interface directly.

Use custom interfaces​

Ask Konnie to connect a discovered table and build the interface around the work: a request card, a filtered queue, a chart beside an input form, or another layout. Blueprints use the same named sources directly. They can query records, read one record, create a record from user input, update it, or delete it without adding a visible table component.

For code authors, ennea.dataSources provides query, get, aggregate, create, update, and delete. Use the source's logical ID rather than its table ID. Field names are the actual column keys from the connected table's schema. This example assumes a source called requests with a status column and an allowed open choice:

const response = await ennea.dataSources.query("requests", {
filter: {
logic: "and",
rules: [{ columnId: "status", operator: "equals", value: "open" }],
},
select: ["status"],
sort: [{ columnId: "status", direction: "asc" }],
offset: 0,
limit: 20,
});
const { rows, total, table } = response.data;

Rows have _id, values and version; read a field as row.values.status. total describes the matching records, while rows contains the requested page. get(sourceId, rowId) returns response.data.row and the current table schema. Successful SDK calls return { ok: true, data: ... }; failed calls throw. Show the error instead of interpreting it as an empty successful result.

Create a pending input once per intended record and retain it for an uncertain retry:

const pending = {
invocationId: ennea.dataSources.createInvocationId(),
values: { status: "open" },
tableVersion: table.version,
expectedTableId: table._id,
};
const created = await ennea.dataSources.create("requests", pending);
const row = created.data.row;

Supply every required field or an applicable schema default. Persist the original expectedTableId with the pending input before dispatch. It pins a resumed request to the Table the user reviewed, even after App publication. If the alias points to another Table, app_data_source_changed requires reconciling the original destination; do not create the same request in the new Table automatically. Keep the same invocation ID and unchanged values until the outcome is known; a changed payload under that ID is rejected. Use a new ID only for a distinct record. An earlier retry cannot recreate a deleted record. Do not automatically start a new creation after an uncertain response.

Updates and deletion use the version of the row the user inspected:

const updated = await ennea.dataSources.update("requests", {
rowId: row._id,
expectedVersion: row.version,
values: { status: "done" },
});
const latestRow = updated.data.row;
// Run only when the user separately chooses to delete this record:
await ennea.dataSources.delete("requests", {
rowId: latestRow._id,
expectedVersion: latestRow.version,
});

The example also assumes an allowed done choice. Updates merge the supplied fields into the current values. On a version conflict, keep the user's draft, reload the record, compare the changes and let the user decide before saving again. Optional tableVersion also detects a changed schema.

aggregate uses the full filtered set rather than the current page:

const summary = await ennea.dataSources.aggregate("requests", {
groupBy: ["status"],
metrics: [{ id: "count", op: "count" }],
limit: 100,
});
const { groups, totalGroups } = summary.data;
// Each group has key.status and values.count.

An App can connect up to 30 data sources. Queries return up to 200 records per page, with at most 20 filter rules and three sort columns. Aggregates support up to three grouping columns and ten metrics (count, sum, avg, min, max); calculations other than count require number columns. Multiple-choice columns cannot be sorted or grouped. Summaries accept at most 10,000 matching records and return up to 200 groups. Check totalGroups before presenting a complete chart and narrow the filter when necessary; do not silently chart an incomplete set.

Invoke SDK writes from an explicit button click (type="button"). Validate inputs with form.reportValidity() and handle Enter locally when useful. The App sandbox blocks native form submission, so a submit button or a form's onSubmit handler cannot be used to save records.

Load records in an effect that ignores responses from an older selection or App context. Requery after confirmed writes and when the interface needs fresh data; a custom Blueprint does not inherit a native view's polling behavior. Provide loading, empty, permission, validation, conflict and retry states, and retain entered values after a failure. Connect a separate App automation action when a user interaction also needs to start a workflow.

Verify and publish​

Save the draft, preview it with agreed test records, then publish through the normal App workflow. Check creating a record, reopening the App, filtering, editing and deletion as the intended user. Table records remain stored when an App is republished.

A source does not grant access beyond the current tenant, site, environment, App audience or user permissions. Concurrent edits show a conflict instead of silently replacing another user's change. Failed saves keep entered values; an uncertain create can be retried safely. Permissions and restricted or deleted records remain enforced by the platform.