Skip to content
Merged
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
129 changes: 23 additions & 106 deletions docs/html-pages/example.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
description: A complete, minimal HTML Page example — initialize the SDK, read rows from the base, render them, and write new linked rows back on submit.
description: A complete, minimal HTML page example — initialize the SDK in a Context module, read rows from the base, render them, and write new linked rows back on submit.
---

# Example: a form that reads and writes
Expand All @@ -15,115 +15,25 @@ flowchart LR
C --> D[on submit: batchAddRows + addRow]
```

It assumes the three tables described in [Getting Started](getting-started.md): **Products**, **OrderItems** (link to Products), and **Orders** (link to OrderItems).

## Single-file version (non-modular)

This is the complete page. It loads the SDK from a CDN, so everything lives in one `index.html` — the non-modular style. Styling is omitted for clarity.

```html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Product Order</title>
</head>
<body>
<div id="products"></div>
<button id="submit">Submit order</button>
<p id="status"></p>

<script src="https://unpkg.com/seatable-html-page-sdk@latest/dist/index.min.js"></script>
<script>
// Quantities chosen by the user: { productRowId: quantity }
const order = {};
let sdk;

async function init() {
// In production __HTML_PAGE_DEV_CONFIG__ is undefined and the SDK
// derives its context from the host app. In development the Vite
// server injects it from src/setting.js. The same line works in both.
sdk = new HTMLPageSDK(window.__HTML_PAGE_DEV_CONFIG__ || null);
await sdk.init();

// Read rows. The payload is under res.data (see SDK Reference > Rows).
const res = await sdk.listRows({ tableName: "Products" });
renderProducts(res.data.results);
}

function renderProducts(products) {
const container = document.getElementById("products");
container.innerHTML = "";

products.forEach((product) => {
const row = document.createElement("div");
row.innerHTML = `
<span>${product.Product_name} (${product.Unit_price})</span>
<input type="number" min="0" value="0" />
`;
// product._id is the row ID — we need it to create the link later.
row.querySelector("input").addEventListener("input", (e) => {
order[product._id] = parseInt(e.target.value, 10) || 0;
});
container.appendChild(row);
});
}

async function submitOrder() {
const status = document.getElementById("status");

// Build one OrderItems row per chosen product.
const orderItemsData = Object.keys(order)
.filter((productId) => order[productId] > 0)
.map((productId) => ({
Quantity: order[productId],
// Link columns take an array of linked row IDs.
Product: [productId],
}));

if (orderItemsData.length === 0) {
status.textContent = "Please choose at least one product.";
return;
}

try {
// 1. Create the order items in one batch call.
const itemsRes = await sdk.batchAddRows({
tableName: "OrderItems",
rowsData: orderItemsData,
});

// batchAddRows returns the created rows under res.data.rows.
// Collect their new IDs to link them to the order.
const orderItemIds = itemsRes.data.rows.map((row) => row._id);

// 2. Create the order, linking the items we just created.
await sdk.addRow({
tableName: "Orders",
rowData: { OrderItems: orderItemIds },
});

status.textContent = "Order submitted.";
} catch (error) {
// A 403 here usually means the API token lacks write permission.
status.textContent = "Submit failed: " + error.message;
}
}

document.getElementById("submit").addEventListener("click", submitOrder);
document.addEventListener("DOMContentLoaded", init);
</script>
</body>
</html>
```
It assumes the three tables described in [Developer setup](getting-started.md): **Products**, **OrderItems** (link to Products), and **Orders** (link to OrderItems).

!!! tip "Linking rows"
!!! tip "Just need a single file?"

If your page is one `index.html` loading the SDK from a CDN — no build step — start
from the [low-code quickstart](low-code-quickstart.md) instead. This example covers the
**modular** developer structure: SDK imported from npm, logic split into modules.

!!! note "One file or modules — a maintainability choice, not a capability one"

Notice the two-step write: first create the `OrderItems` rows with `batchAddRows`, then read their `_id` values from `res.data.rows` and pass them as an array to the `Orders` row's link column. Link columns always take an array of linked row IDs — see [`addRow`](sdk/rows.md#add-rows).
Modules do not unlock anything a single file cannot do — the
[low-code quickstart](low-code-quickstart.md) reads and writes linked tables from one
`index.html` too. Splitting into modules pays off as a page *grows*: easier to
navigate, test and reuse. Reach for them when the file gets unwieldy, not when the
logic gets ambitious.

## Modular version
## Wrap base access in a Context class

For anything beyond a simple page, split the logic into modules and import the SDK from the npm package. The template's `src/esm` directory does exactly this. A common pattern is to wrap all base access in a single `Context` class, keeping SDK calls out of your UI code:
As a page grows, split the logic into modules and import the SDK from the npm package. The template's `src/esm` directory does exactly this. A common pattern is to wrap all base access in a single `Context` class, keeping SDK calls out of your UI code:

```js
import { HTMLPageSDK } from "seatable-html-page-sdk";
Expand Down Expand Up @@ -171,6 +81,13 @@ document.addEventListener("DOMContentLoaded", async () => {
});
```

!!! tip "Linking rows"

Notice the two-step write in `submitOrder`: first create the `OrderItems` rows with
`batchAddRows`, then read their `_id` values from `res.data.rows` and pass them as an
array to the `Orders` row's link column. Link columns always take an array of linked
row IDs — see [`addRow`](sdk/rows.md#add-rows).

## Next steps

- [SDK Reference: Rows](sdk/rows.md) — full parameters and return shapes for every row method.
Expand Down
24 changes: 15 additions & 9 deletions docs/html-pages/getting-started.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,16 @@
---
description: Set up, develop, build and upload a SeaTable HTML Page. Walks through the simple form template with Vite, the SDK, and the uploadable ZIP package.
description: Set up, develop, build and upload a SeaTable HTML page with the full developer toolchain. Walks through the simple form template with Vite, the SDK, and the uploadable ZIP package.
---

# Getting Started
# Developer setup

This guide walks through building an HTML Page from the official [simple form template](https://github.com/seatable/seatable-html-page-template-simple-form): a form that writes submitted records into a base. By the end you will have a packaged ZIP that you can upload to a Universal App.
This is the **developer setup**: you clone the official template and use a full JavaScript toolchain (Node.js, npm, a Vite dev server with live reload, and a build step). It suits larger or more complex pages.

!!! tip "Prefer no toolchain?"

If you just want a form or a small tool, you can build a page in a visual editor with no Node.js or npm at all — see the [Low-code quickstart](low-code-quickstart.md). You can always move up to this setup later.

This guide walks through building an HTML page from the official [simple form template](https://github.com/seatable/seatable-html-page-template-simple-form): a form that writes submitted records into a base. By the end you will have a packaged ZIP that you can upload to a Universal App.

The template ships the build configuration and project structure you need. It supports two development styles:

Expand All @@ -23,11 +29,11 @@ Choose the approach that fits the complexity of your page. Both produce the same

Create them in your base before running the page, or adapt the table and field names in the template's source.

## Before you start: add an HTML Page in the app
## Before you start: add an HTML page in the app

In your Universal App, add a new page and choose **Add HTML page**. This creates the empty page you will later upload your build to, and it surfaces the `server`, `appUuid` and `pageId` values you need for local development ([step 3](#3-configure-local-development)).

![Adding an HTML Page to a Universal App](../media/html-page-add.png)
![Adding an HTML page to a Universal App](../media/html-page-add.png)

## 1. Get the template

Expand Down Expand Up @@ -69,11 +75,11 @@ These values are registered to `window.__HTML_PAGE_DEV_CONFIG__` and picked up b
!!! note "Where the values come from"

- `accountToken` — an API token you generate in the base in advance. See [how to create API tokens](https://seatable.com/help/create-api-tokens/).
- `server`, `appUuid` and `pageId` — shown under **HTML Page development information** in the page's configuration (see below).
- `server`, `appUuid` and `pageId` — shown under **HTML page development information** in the page's configuration (see below).

The HTML Page configuration shows these values ready to copy, alongside the upload area you will use later:
The HTML page configuration shows these values ready to copy, alongside the upload area you will use later:

![HTML Page configuration with development information and upload area](../media/html-page-config.png)
![HTML page configuration with development information and upload area](../media/html-page-config.png)

## 4. Run the development server

Expand All @@ -99,7 +105,7 @@ This single command cleans the output, runs the Vite build (into `dist`), and pa

## 6. Upload and test

1. In SeaTable, open the configuration of the HTML Page in your Universal App.
1. In SeaTable, open the configuration of the HTML page in your Universal App.
2. Drag the generated ZIP into the **Upload HTML page file** area (the same configuration shown in [step 3](#3-configure-local-development)).
3. Open the app preview, fill in the form, and submit it.
4. Return to the base and confirm that the corresponding records were created.
Expand Down
51 changes: 40 additions & 11 deletions docs/html-pages/index.md
Original file line number Diff line number Diff line change
@@ -1,22 +1,22 @@
---
description: Build interactive HTML Pages for SeaTable Universal Apps. Learn how a page reads and writes base data through the seatable-html-page-sdk.
description: Build interactive HTML pages for SeaTable Universal Apps. Learn how a page reads and writes base data through the seatable-html-page-sdk.
---

# HTML Pages
# HTML pages

Starting with SeaTable 6.2, a Universal App can contain a new page type: the **HTML Page**. You upload a packaged HTML/JavaScript/CSS bundle, and SeaTable renders it as a full page inside the app.
Starting with SeaTable 6.2, a Universal App can contain a new page type: the **HTML page**. You upload a packaged HTML/JavaScript/CSS bundle, and SeaTable renders it as a full page inside the app.

A static bundle on its own can only display fixed content. To turn an HTML Page into a real application — a custom form, a dashboard, a calculator — it needs to read from and write to the base. That data exchange runs through the [`seatable-html-page-sdk`](https://www.npmjs.com/package/seatable-html-page-sdk).
A static bundle on its own can only display fixed content. To turn an HTML page into a real application — a custom form, a dashboard, a calculator — it needs to read from and write to the base. That data exchange runs through the [`seatable-html-page-sdk`](https://www.npmjs.com/package/seatable-html-page-sdk).

This section is written for developers. It covers how to set up a project, how to develop and package a page, and the full SDK reference.

## Architecture

An HTML Page is rendered in a sandboxed context inside the Universal App. It never talks to the base directly. Instead, the SDK provides a messaging bridge to the app, which performs the actual data operations.
An HTML page is rendered in a sandboxed context inside the Universal App. It never talks to the base directly. Instead, the SDK provides a messaging bridge to the app, which performs the actual data operations.

```mermaid
flowchart LR
A[HTML Page] -->|seatable-html-page-sdk| B[Universal App]
A[HTML page] -->|seatable-html-page-sdk| B[Universal App]
B -->|API| C[(Base)]
C --> B
B --> A
Expand All @@ -30,15 +30,44 @@ The SDK offers:
## Prerequisites

- SeaTable 6.2 or later.
- A Universal App with an HTML Page added to it.
- An API token generated in the base (used during local development).
- Node.js and npm for building the page.
- A Universal App with an HTML page added to it.

The developer setup additionally needs Node.js and npm, and an API token generated in the base for local development. The low-code approach needs neither.

## Two ways to build

The same kind of page can be built two ways. Pick the one that matches how you like to work — both produce the same uploadable ZIP and use the same SDK.

<div class="grid cards" markdown>

- :material-cursor-default-click:{ .lg .middle } __Low-code quickstart__

---

Design the page in any visual (WYSIWYG) HTML editor, connect it to your base with ready-made copy-paste snippets, and upload. No Node.js, no npm, no dev server.

Best for forms, dashboards and small tools.

[:octicons-arrow-right-24: Low-code quickstart](low-code-quickstart.md)

- :material-code-tags:{ .lg .middle } __Developer setup__

---

Clone the official template and use a full toolchain: modular files, a live-reload dev server, npm scripts and a real build.

Best for larger or more complex pages.

[:octicons-arrow-right-24: Developer setup](getting-started.md)

</div>

## Where to start

- [Getting Started](getting-started.md) — set up the project, develop locally, build and upload a page. We follow the official [simple form template](https://github.com/seatable/seatable-html-page-template-simple-form) end to end.
- [Low-code quickstart](low-code-quickstart.md) — build a page with a visual editor and copy-paste snippets, no toolchain.
- [Developer setup](getting-started.md) — set up the project, develop locally, build and upload a page. We follow the official [simple form template](https://github.com/seatable/seatable-html-page-template-simple-form) end to end.
- [SDK Reference](sdk/initialization.md) — installation, initialization, and the full API for rows, files and images.

!!! tip "Example project"

The [`seatable-html-page-template-simple-form`](https://github.com/seatable/seatable-html-page-template-simple-form) repository contains a complete, buildable form page. It is the running example used throughout this section.
The [`seatable-html-page-template-simple-form`](https://github.com/seatable/seatable-html-page-template-simple-form) repository contains a complete, buildable form page. It is the running example used throughout the developer setup.
Loading
Loading