Skip to content

feat: Add SeaTable as native data source plugin#41715

Open
christophdb wants to merge 7 commits intoappsmithorg:releasefrom
christophdb:feat/add-seatable-plugin
Open

feat: Add SeaTable as native data source plugin#41715
christophdb wants to merge 7 commits intoappsmithorg:releasefrom
christophdb:feat/add-seatable-plugin

Conversation

@christophdb
Copy link
Copy Markdown

@christophdb christophdb commented Apr 7, 2026

Summary

  • Adds a native data source plugin for SeaTable, an open-source database platform (spreadsheet-database hybrid)
  • Supports CRUD operations, metadata/schema discovery, and SQL queries
  • Uses UQI editor pattern (like Firestore plugin), stateless HTTP via WebClient

This is a resubmission of #41629, which was auto-closed due to inactivity. No code changes, just rebased on latest release.

Features

Command Method Endpoint
List Rows GET /api/v2/dtables/{uuid}/rows/
Get Row GET /api/v2/dtables/{uuid}/rows/{row_id}/
Create Row POST /api/v2/dtables/{uuid}/rows/
Update Row PUT /api/v2/dtables/{uuid}/rows/
Delete Row DELETE /api/v2/dtables/{uuid}/rows/
List Tables GET /api/v2/dtables/{uuid}/metadata/
SQL Query POST /api/v2/dtables/{uuid}/sql/

Implementation Details

  • Authentication: SeaTable API Token -> Base Access Token (two-step, automatic)
  • Plugin type: PluginExecutor<Void> (stateless HTTP, no persistent connection)
  • Editor: UQI form-based (separate JSON per command, like Firestore)
  • Schema discovery: getStructure() via metadata endpoint
  • Tests: Unit tests with MockWebServer

Verified against live SeaTable instance

All API operations have been tested and verified against a live SeaTable server:

Operation Status Details
Token Exchange pass API token exchanged, dtable_server and dtable_uuid returned correctly
List Tables pass Metadata endpoint returns tables with columns and types
List Rows pass convert_keys=true returns column names, pagination via limit/start works
Get Row pass Single row fetched by ID with convert_keys=true
Create Row pass Row inserted, row_ids and first_row returned
Update Row pass Row updated by ID, {"success": true} confirmed
Delete Row pass Row deleted, subsequent GET returns 404
SQL Query pass convert_keys=true in body works, results and metadata returned

Test plan

  • Unit tests with MockWebServer (validation, connectivity, CRUD/SQL, metadata)
  • All 7 commands tested against a live SeaTable instance
  • Token exchange and dtable_server URL handling verified
  • Error handling verified (invalid token, missing parameters)
  • Integration test in running Appsmith instance

References

Summary by CodeRabbit

Release Notes

New Features

  • SeaTable database connector now available. Connect to SeaTable bases using Server URL and API token authentication. Support for listing, fetching, creating, updating, and deleting rows; retrieving table metadata; and executing SQL queries.

Add a native Appsmith data source plugin for SeaTable, an open-source
database platform (spreadsheet-database hybrid).

Supported operations:
- List Rows (with filtering, sorting, pagination)
- Get Row (by ID)
- Create Row
- Update Row
- Delete Row
- List Tables (metadata/schema discovery)
- SQL Query

Authentication uses SeaTable's API Token, which is automatically
exchanged for a base access token. The plugin is stateless (HTTP
via WebClient) and follows the UQI editor pattern (like Firestore).

All API endpoints verified against the SeaTable OpenAPI specification
and tested against a live SeaTable instance.

Closes appsmithorg#41627
- Add private constructors to FieldName and SeaTableErrorMessages utility classes
- Use MessageFormat.format() in SeaTablePluginError instead of super delegation
- Add 30s timeout to all HTTP requests (fetchAccessToken, executeRequest, getStructure)
- Add null-checks for access token response fields
- Add defensive null-checks for metadata parsing (table name, column name/type)
- Add Javadoc to all public and significant private methods
- Add timeout validation (min: 1) and placeholder to setting.json
- Use FieldName constants instead of string literals in tests
- Add HTTP request assertions (method, path, headers, body) to all tests via MockWebServer.takeRequest()
- Add getErrorAction() and AppsmithErrorAction to SeaTablePluginError (match BasePluginError interface fully, follow FirestorePluginError pattern)
- Validate required form fields before fetching access token (avoid unnecessary network calls)
- Guard against null executeActionDTO.getParams() in smart substitution
- Initialize structure.setTables() before early returns in getStructure()
- Switch tests from @BeforeAll/@afterall to @BeforeEach/@AfterEach for per-test MockWebServer isolation
SeaTable should appear under "SaaS Integrations" alongside Airtable
and Google Sheets, not under "APIs". Also fix documentationLink URL.
- Use MessageFormat in SeaTablePluginError.getMessage() for consistency
  with PostgresPluginError pattern
- Add defensive null checks in fetchAccessToken() to prevent NPE when
  URL or authentication is missing
- Use Appsmith-hosted icon URL instead of external seatable.com favicon
- Make migration changeset idempotent by fetching persisted plugin on
  duplicate key
- Mark FieldName as final (utility class pattern)
- Remove duplicate validation in command methods (already handled by validateCommandInputs)
- Reuse buildRequest helper in getStructure instead of inline WebClient
- Fail fast on unsupported commands before token exchange
- Use Mono.empty() instead of null in validateCommandInputs
- Propagate metadata parsing errors instead of silently returning empty schema
@christophdb
Copy link
Copy Markdown
Author

Hi team! This is a resubmission of #41629, which was auto-closed due to inactivity before it could be reviewed.

The plugin is fully functional and tested. I'd appreciate it if a maintainer could take a look when you get a chance. Happy to address any feedback.

Thanks!

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Apr 7, 2026

Walkthrough

This PR introduces SeaTable as a native data source plugin for Appsmith. It includes the Maven module configuration, Java plugin executor with stateless HTTP operations, datasource authentication and schema discovery, seven UI editor forms for commands (LIST_ROWS, GET_ROW, CREATE_ROW, UPDATE_ROW, DELETE_ROW, LIST_TABLES, SQL_QUERY), comprehensive test coverage with MockWebServer, and database migration to register the plugin.

Changes

Cohort / File(s) Summary
Maven Configuration
app/server/appsmith-plugins/pom.xml, app/server/appsmith-plugins/seaTablePlugin/pom.xml
Added seaTablePlugin module to parent; configured new plugin POM with shade and dependency plugins for JAR packaging and manifest metadata.
Plugin Implementation
app/server/appsmith-plugins/seaTablePlugin/src/main/java/com/external/plugins/SeaTablePlugin.java
Core executor implementing PluginExecutor<Void> with access token exchange, command routing (7 commands), per-command validation, HTTP request building, response parsing, and schema discovery via metadata endpoint.
Error Handling & Constants
app/server/appsmith-plugins/seaTablePlugin/src/main/java/com/external/plugins/exceptions/SeaTablePluginError.java, SeaTableErrorMessages.java, com/external/constants/FieldName.java
Added error enum (BasePluginError implementation), error message constants, and field name constants for request/SQL keys.
Editor UI Forms
app/server/appsmith-plugins/seaTablePlugin/src/main/resources/editor/root.json, listRows.json, getRow.json, createRow.json, updateRow.json, deleteRow.json, listTables.json, sqlQuery.json
Declared command dropdown and seven command-specific form sections with conditional rendering, field bindings, and smart substitution for body inputs.
Plugin Configuration
app/server/appsmith-plugins/seaTablePlugin/src/main/resources/plugin.properties, form.json, setting.json
Added plugin metadata, datasource connection form (Server URL & API Token), and action settings (executeOnLoad, confirmBeforeExecute, timeout).
Tests & Migration
app/server/appsmith-plugins/seaTablePlugin/src/test/java/com/external/plugins/SeaTablePluginTest.java, app/server/appsmith-server/src/main/java/com/appsmith/server/migrations/DatabaseChangelog2.java
Comprehensive test suite with MockWebServer covering all 7 commands, validation, schema discovery, and negative cases; Mongock migration to register plugin across workspaces.

Sequence Diagram

sequenceDiagram
    participant Client as Appsmith Client
    participant Executor as SeaTablePlugin Executor
    participant SeaTable as SeaTable API
    participant DB as SeaTable Metadata

    Client->>Executor: testDatasource(url, apiToken)
    Executor->>SeaTable: GET /api/v2.1/dtable/app-access-token/<br/>(auth: apiToken)
    SeaTable-->>Executor: {access_token, dtable_uuid, dtable_server}
    Executor-->>Client: DatasourceTestResult (success/failure)

    Client->>Executor: executeParameterized(command=LIST_ROWS, ...)
    Executor->>SeaTable: GET /api/v2.1/dtables/{uuid}/rows/<br/>(auth: access_token)
    SeaTable-->>Executor: rows[] JSON
    Executor-->>Client: ActionExecutionResult

    Client->>Executor: getStructure()
    Executor->>SeaTable: GET /api/v2.1/dtables/{uuid}/metadata/<br/>(auth: access_token)
    SeaTable-->>DB: fetch tables & columns
    DB-->>Executor: metadata.tables[]
    Executor-->>Client: DatasourceStructure
Loading

Estimated Code Review Effort

🎯 4 (Complex) | ⏱️ ~50 minutes

Poem

🌊 SeaTable rows cascade into Appsmith's harbor,
Seven commands sail smoothly through the waves,
Token-blessed REST calls dance with grace,
Where spreadsheets and databases embrace! 📊✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 55.36% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly describes the main change: adding SeaTable as a native data source plugin to Appsmith.
Description check ✅ Passed The description covers objectives, features, implementation details, verification, test plan, and references. However, it does not follow the repository template structure with explicit 'Fixes #IssueNumber' and automation sections.
Linked Issues check ✅ Passed The PR fully implements all coding requirements from #41627: SeaTable plugin with CRUD operations, metadata discovery, SQL queries, two-step authentication, stateless WebClient design, UQI editor, unit tests with MockWebServer, and migration changeset.
Out of Scope Changes check ✅ Passed All changes are scoped to the SeaTable plugin implementation and its registration. The only non-plugin file is DatabaseChangelog2.java, which adds the required migration changeset for plugin registration—directly in scope.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (2)
app/server/appsmith-plugins/seaTablePlugin/src/test/java/com/external/plugins/SeaTablePluginTest.java (2)

515-559: Assert that validation fails before the token exchange.

These tests currently prove the exception, but not the fail-fast behavior. If a future refactor fetches /app-access-token/ before validating command, tableName, or rowId, they would still pass.

✅ Small test hardening
 StepVerifier.create(resultMono)
         .expectErrorMatches(e -> e instanceof AppsmithPluginException
                 && e.getMessage().contains("Missing command"))
         .verify();
+assertEquals(0, mockWebServer.getRequestCount());

Apply the same assertion to the missing-table-name and missing-row-id cases.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@app/server/appsmith-plugins/seaTablePlugin/src/test/java/com/external/plugins/SeaTablePluginTest.java`
around lines 515 - 559, Add the same "fail-fast before token exchange" assertion
used in testMissingCommand to both testListRows_missingTableName and
testGetRow_missingRowId: do not enqueueAccessTokenResponse() (or if you must
call it, assert the access-token endpoint on the mock server was not invoked)
and after invoking pluginExecutor.executeParameterized(...) and the StepVerifier
checks, assert that no token request was made (e.g.,
mockServer.getRequestCount() == 0 or equivalent). Update the two tests
(testListRows_missingTableName and testGetRow_missingRowId) to include this
assertion so validation is proven to run before any call to
enqueueAccessTokenResponse()/token exchange.

320-386: Add one test for the body-substitution path.

CREATE_ROW and UPDATE_ROW only exercise literal JSON bodies here. A regression in executeParameterized()'s mustache replacement, or in the smartSubstitution=false branch, would slip through.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@app/server/appsmith-plugins/seaTablePlugin/src/test/java/com/external/plugins/SeaTablePluginTest.java`
around lines 320 - 386, Add a unit test in SeaTablePluginTest that covers the
mustache/body-substitution path: create an ActionConfiguration (via
createActionConfig) for CREATE_ROW and another for UPDATE_ROW where
FieldName.BODY contains a template (e.g. "{\"Name\":\"{{name}}\"}" or
"{\"Age\":{{age}}}") and ensure smartSubstitution is disabled/false on the
ActionConfiguration so the code path that performs manual mustache replacement
in executeParameterized() is exercised; call
pluginExecutor.executeParameterized(...) with a matching ExecuteActionDTO (or
provide the template variables in the DTO/context used by substitution), assert
execution success, then inspect the RecordedRequest body (like in
testCreateRow/testUpdateRow) to verify the substituted values appear in the
outgoing JSON. Ensure tests reference createActionConfig, FieldName.BODY,
executeParameterized, and the RecordedRequest assertions to locate changes.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@app/server/appsmith-plugins/seaTablePlugin/src/main/java/com/external/plugins/SeaTablePlugin.java`:
- Around line 513-519: The code currently wraps any JSON (arrays/scalars)
returned by objectMapper.readTree into the SeaTable "rows"/"updates" payload;
update both executeCreateRow(...) and executeUpdateRow(...) to ensure the parsed
JsonNode (the variable rowData from objectMapper.readTree) is an object node
before building the wrapper: if rowData == null or !rowData.isObject(), return
or throw a clear validation error (rejecting non-object bodies) rather than
proceeding to create the wrapper/rows ArrayNode and requestBody; keep the same
wrapper creation (wrapper.put("table_name", ...), rowsArray.add(rowData),
wrapper.set("rows", rowsArray), requestBody =
objectMapper.writeValueAsString(wrapper)) only after the isObject check passes.
- Around line 718-725: In getStructure(), do not silently return an empty
structure when the response JSON lacks the expected "metadata" or
"metadata.tables" fields; instead treat that as an error and propagate/fail
fast. Locate the checks on JsonNode metadata and JsonNode tablesNode in
SeaTablePlugin.getStructure() and replace the early "return structure" behavior
with raising/returning an appropriate error (e.g., throw a checked/unchecked
exception or return a failed Result/Action with a clear message) that includes
the raw response or an explanatory message so callers see the discovery failure
instead of an empty schema.

In
`@app/server/appsmith-plugins/seaTablePlugin/src/main/resources/editor/listRows.json`:
- Around line 23-74: The UI exposes a WHERE_CLAUSE (configProperty
actionConfiguration.formData.where.data) but executeListRows in
SeaTablePlugin.java never reads it; update executeListRows to parse
actionConfiguration.formData.where.data (the WHERE_CLAUSE structure), map its
comparisonTypes and logicalTypes to SeaTable filter syntax, build the filter
expression and include it in the API request (or query parameters) sent to list
rows; ensure you handle nestedLevels and all comparison values (EQ, NOT_EQ, LT,
LTE, GT, GTE, CONTAINS) and fallback safely for unsupported ops, or if you
prefer not to implement filtering remove the WHERE_CLAUSE control from
listRows.json to avoid a dangling UI.

---

Nitpick comments:
In
`@app/server/appsmith-plugins/seaTablePlugin/src/test/java/com/external/plugins/SeaTablePluginTest.java`:
- Around line 515-559: Add the same "fail-fast before token exchange" assertion
used in testMissingCommand to both testListRows_missingTableName and
testGetRow_missingRowId: do not enqueueAccessTokenResponse() (or if you must
call it, assert the access-token endpoint on the mock server was not invoked)
and after invoking pluginExecutor.executeParameterized(...) and the StepVerifier
checks, assert that no token request was made (e.g.,
mockServer.getRequestCount() == 0 or equivalent). Update the two tests
(testListRows_missingTableName and testGetRow_missingRowId) to include this
assertion so validation is proven to run before any call to
enqueueAccessTokenResponse()/token exchange.
- Around line 320-386: Add a unit test in SeaTablePluginTest that covers the
mustache/body-substitution path: create an ActionConfiguration (via
createActionConfig) for CREATE_ROW and another for UPDATE_ROW where
FieldName.BODY contains a template (e.g. "{\"Name\":\"{{name}}\"}" or
"{\"Age\":{{age}}}") and ensure smartSubstitution is disabled/false on the
ActionConfiguration so the code path that performs manual mustache replacement
in executeParameterized() is exercised; call
pluginExecutor.executeParameterized(...) with a matching ExecuteActionDTO (or
provide the template variables in the DTO/context used by substitution), assert
execution success, then inspect the RecordedRequest body (like in
testCreateRow/testUpdateRow) to verify the substituted values appear in the
outgoing JSON. Ensure tests reference createActionConfig, FieldName.BODY,
executeParameterized, and the RecordedRequest assertions to locate changes.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: cec430bf-5481-4f3d-8084-6608a0d9652e

📥 Commits

Reviewing files that changed from the base of the PR and between 89e51a7 and cdaba44.

📒 Files selected for processing (19)
  • app/server/appsmith-plugins/pom.xml
  • app/server/appsmith-plugins/seaTablePlugin/pom.xml
  • app/server/appsmith-plugins/seaTablePlugin/src/main/java/com/external/constants/FieldName.java
  • app/server/appsmith-plugins/seaTablePlugin/src/main/java/com/external/plugins/SeaTablePlugin.java
  • app/server/appsmith-plugins/seaTablePlugin/src/main/java/com/external/plugins/exceptions/SeaTableErrorMessages.java
  • app/server/appsmith-plugins/seaTablePlugin/src/main/java/com/external/plugins/exceptions/SeaTablePluginError.java
  • app/server/appsmith-plugins/seaTablePlugin/src/main/resources/editor/createRow.json
  • app/server/appsmith-plugins/seaTablePlugin/src/main/resources/editor/deleteRow.json
  • app/server/appsmith-plugins/seaTablePlugin/src/main/resources/editor/getRow.json
  • app/server/appsmith-plugins/seaTablePlugin/src/main/resources/editor/listRows.json
  • app/server/appsmith-plugins/seaTablePlugin/src/main/resources/editor/listTables.json
  • app/server/appsmith-plugins/seaTablePlugin/src/main/resources/editor/root.json
  • app/server/appsmith-plugins/seaTablePlugin/src/main/resources/editor/sqlQuery.json
  • app/server/appsmith-plugins/seaTablePlugin/src/main/resources/editor/updateRow.json
  • app/server/appsmith-plugins/seaTablePlugin/src/main/resources/form.json
  • app/server/appsmith-plugins/seaTablePlugin/src/main/resources/plugin.properties
  • app/server/appsmith-plugins/seaTablePlugin/src/main/resources/setting.json
  • app/server/appsmith-plugins/seaTablePlugin/src/test/java/com/external/plugins/SeaTablePluginTest.java
  • app/server/appsmith-server/src/main/java/com/appsmith/server/migrations/DatabaseChangelog2.java

Comment on lines +513 to +519
JsonNode rowData = objectMapper.readTree(StringUtils.isBlank(body) ? "{}" : body);
ObjectNode wrapper = objectMapper.createObjectNode();
wrapper.put("table_name", tableName);
ArrayNode rowsArray = objectMapper.createArrayNode();
rowsArray.add(rowData);
wrapper.set("rows", rowsArray);
requestBody = objectMapper.writeValueAsString(wrapper);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Reject non-object row bodies locally.

readTree() accepts arrays and scalars here, so inputs like [] or "foo" still get wrapped into rows / updates and only fail after the HTTP call. Both commands should require a JSON object before building the SeaTable payload.

🛡️ Tighten the body validation
 JsonNode rowData = objectMapper.readTree(StringUtils.isBlank(body) ? "{}" : body);
+if (!rowData.isObject()) {
+    return Mono.error(new AppsmithPluginException(
+            SeaTablePluginError.INVALID_BODY_ERROR,
+            "Row body must be a JSON object."));
+}

Apply the same check in both executeCreateRow(...) and executeUpdateRow(...).

Also applies to: 544-556

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@app/server/appsmith-plugins/seaTablePlugin/src/main/java/com/external/plugins/SeaTablePlugin.java`
around lines 513 - 519, The code currently wraps any JSON (arrays/scalars)
returned by objectMapper.readTree into the SeaTable "rows"/"updates" payload;
update both executeCreateRow(...) and executeUpdateRow(...) to ensure the parsed
JsonNode (the variable rowData from objectMapper.readTree) is an object node
before building the wrapper: if rowData == null or !rowData.isObject(), return
or throw a clear validation error (rejecting non-object bodies) rather than
proceeding to create the wrapper/rows ArrayNode and requestBody; keep the same
wrapper creation (wrapper.put("table_name", ...), rowsArray.add(rowData),
wrapper.set("rows", rowsArray), requestBody =
objectMapper.writeValueAsString(wrapper)) only after the isObject check passes.

Comment on lines +718 to +725
JsonNode metadata = json.get("metadata");
if (metadata == null) {
return structure;
}
JsonNode tablesNode = metadata.get("tables");
if (tablesNode == null || !tablesNode.isArray()) {
return structure;
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Don't turn a malformed metadata response into an empty schema.

If the metadata endpoint returns valid JSON without metadata.tables—for example an API error payload or an unexpected response shape—getStructure() currently reports an empty base instead of surfacing the failure. That makes schema discovery look successful when it actually broke.

🚨 Fail fast on an invalid metadata shape
 JsonNode metadata = json.get("metadata");
- if (metadata == null) {
-     return structure;
- }
+ if (metadata == null) {
+     throw Exceptions.propagate(new AppsmithPluginException(
+             SeaTablePluginError.QUERY_EXECUTION_FAILED,
+             String.format(
+                     SeaTableErrorMessages.QUERY_EXECUTION_FAILED_ERROR_MSG,
+                     "Invalid SeaTable metadata response: missing metadata node")));
+ }

 JsonNode tablesNode = metadata.get("tables");
- if (tablesNode == null || !tablesNode.isArray()) {
-     return structure;
- }
+ if (tablesNode == null || !tablesNode.isArray()) {
+     throw Exceptions.propagate(new AppsmithPluginException(
+             SeaTablePluginError.QUERY_EXECUTION_FAILED,
+             String.format(
+                     SeaTableErrorMessages.QUERY_EXECUTION_FAILED_ERROR_MSG,
+                     "Invalid SeaTable metadata response: metadata.tables must be an array")));
+ }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@app/server/appsmith-plugins/seaTablePlugin/src/main/java/com/external/plugins/SeaTablePlugin.java`
around lines 718 - 725, In getStructure(), do not silently return an empty
structure when the response JSON lacks the expected "metadata" or
"metadata.tables" fields; instead treat that as an error and propagate/fail
fast. Locate the checks on JsonNode metadata and JsonNode tablesNode in
SeaTablePlugin.getStructure() and replace the early "return structure" behavior
with raising/returning an appropriate error (e.g., throw a checked/unchecked
exception or return a failed Result/Action with a clear message) that includes
the raw response or an explanatory message so callers see the discovery failure
instead of an empty schema.

Comment on lines +23 to +74
{
"controlType": "SINGLE_COLUMN_ZONE",
"identifier": "LIST-ROWS-Z2",
"children": [
{
"label": "Where",
"configProperty": "actionConfiguration.formData.where.data",
"nestedLevels": 1,
"controlType": "WHERE_CLAUSE",
"logicalTypes": [
{
"label": "AND",
"value": "AND"
},
{
"label": "OR",
"value": "OR"
}
],
"comparisonTypes": [
{
"label": "==",
"value": "EQ"
},
{
"label": "!=",
"value": "NOT_EQ"
},
{
"label": "<",
"value": "LT"
},
{
"label": "<=",
"value": "LTE"
},
{
"label": ">",
"value": "GT"
},
{
"label": ">=",
"value": "GTE"
},
{
"label": "contains",
"value": "CONTAINS"
}
]
}
]
},
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify that the where clause is not being processed in executeListRows
ast-grep --pattern $'private Mono<ActionExecutionResult> executeListRows($_, $_, $_) {
  $$$
}'

# Also search for any usage of "where" field in the plugin
rg -n "where" --type=java app/server/appsmith-plugins/seaTablePlugin/

Repository: appsmithorg/appsmith

Length of output: 209


🏁 Script executed:

#!/bin/bash
# Find the executeListRows method implementation
rg -n "executeListRows" --type=java app/server/appsmith-plugins/seaTablePlugin/ -A 30

# Also search for how formData.where is used
rg -n "formData.*where" --type=java app/server/appsmith-plugins/seaTablePlugin/

# Check the SeaTablePlugin main class
fd -e "SeaTablePlugin.java" app/server/appsmith-plugins/seaTablePlugin/

Repository: appsmithorg/appsmith

Length of output: 10626


🏁 Script executed:

#!/bin/bash
# Get the complete executeListRows method
sed -n '447,500p' app/server/appsmith-plugins/seaTablePlugin/src/main/java/com/external/plugins/SeaTablePlugin.java

# Also search for any WHERE_CLAUSE or where references in context of list/filter operations
rg -n "WHERE|where" --type=java app/server/appsmith-plugins/seaTablePlugin/src/main/java/com/external/plugins/SeaTablePlugin.java -B 2 -A 2

Repository: appsmithorg/appsmith

Length of output: 2701


WHERE clause UI is defined but not processed by the backend.

The executeListRows method (lines 447-487 in SeaTablePlugin.java) only extracts tableName, limit, offset, orderBy, and direction. The where.data field from this UI element is never read or translated into SeaTable API filter expressions.

Either implement filter logic in the executor or remove the WHERE_CLAUSE control to avoid misleading users.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@app/server/appsmith-plugins/seaTablePlugin/src/main/resources/editor/listRows.json`
around lines 23 - 74, The UI exposes a WHERE_CLAUSE (configProperty
actionConfiguration.formData.where.data) but executeListRows in
SeaTablePlugin.java never reads it; update executeListRows to parse
actionConfiguration.formData.where.data (the WHERE_CLAUSE structure), map its
comparisonTypes and logicalTypes to SeaTable filter syntax, build the filter
expression and include it in the API request (or query parameters) sent to list
rows; ensure you handle nestedLevels and all comparison values (EQ, NOT_EQ, LT,
LTE, GT, GTE, CONTAINS) and fallback safely for unsupported ops, or if you
prefer not to implement filtering remove the WHERE_CLAUSE control from
listRows.json to avoid a dangling UI.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat: Add SeaTable as native data source plugin

1 participant