From 3786bfe160fc729e167327bb43dd0964f2c2dd95 Mon Sep 17 00:00:00 2001 From: zwfxxxxx Date: Wed, 5 Aug 2026 20:09:42 +0800 Subject: [PATCH 1/4] add queryRows API for HTML pages --- src/apis/html-page-api.js | 9 +++++++ src/iframe-adapter.js | 1 + src/sdk.js | 19 +++++++++++++ tests/html-page-api.test.js | 53 +++++++++++++++++++++++++++++++++++++ tests/sdk-init.test.js | 18 +++++++++++++ tests/sdk.test.js | 42 +++++++++++++++++++++++++++++ 6 files changed, 142 insertions(+) diff --git a/src/apis/html-page-api.js b/src/apis/html-page-api.js index 003127c..42f56e2 100644 --- a/src/apis/html-page-api.js +++ b/src/apis/html-page-api.js @@ -58,6 +58,15 @@ class HTMLPageAPI { return this.req.get(url, { params }); } + queryRows(page_id, table_id, filters, start, limit, query_config) { + const url = `${this.server}api/v2.1/universal-apps/${this.appUuid}/html-page-rows/query/`; + const data = { page_id, table_id, filters, start, limit }; + if (query_config && typeof query_config === 'object') { + data.query_config = query_config; + } + return this.req.post(url, data); + } + listCollaborators() { const url = `${this.server}api/v2.1/universal-apps/${this.appUuid}/html-page-collaborators/`; return this.req.get(url); diff --git a/src/iframe-adapter.js b/src/iframe-adapter.js index d62d2c3..0ac76c8 100644 --- a/src/iframe-adapter.js +++ b/src/iframe-adapter.js @@ -10,6 +10,7 @@ export const POST_MESSAGE_REQUEST_TYPE = { GET_ACCESS_TOKEN: 'get_access_token', GET_APP_UUID: 'get_app_uuid', GET_PAGE_ID: 'get_page_id', + GET_QUERY_TABLE_CONFIGS: 'get_query_table_configs', }; const WINDOW_EVENT_SOURCE_TYPE = { diff --git a/src/sdk.js b/src/sdk.js index 4ab9342..7980c47 100644 --- a/src/sdk.js +++ b/src/sdk.js @@ -21,6 +21,10 @@ export class HTMLPageSDK { if (!this.options.pageId) { this.options.pageId = await this.iframeAdapter.request(POST_MESSAGE_REQUEST_TYPE.GET_PAGE_ID); } + if (this.options.pageId === 'ai_agent' && !Array.isArray(this.options.queryTableConfigs)) { + const queryTableConfigs = await this.iframeAdapter.request(POST_MESSAGE_REQUEST_TYPE.GET_QUERY_TABLE_CONFIGS); + this.options.queryTableConfigs = Array.isArray(queryTableConfigs) ? queryTableConfigs : []; + } if (this.options.accountToken) { // dev: try to get access-token via accountToken const { server, accountToken, appUuid } = this.options; @@ -38,6 +42,21 @@ export class HTMLPageSDK { return this.htmlPageAPI.listRows(this.options.pageId, tableName, start, limit); } + queryRows({ tableId, filters, start, limit }) { + let queryConfig; + if (this.options.pageId === 'ai_agent' && tableId && Array.isArray(this.options.queryTableConfigs)) { + const tableConfig = this.options.queryTableConfigs.find(config => config?.table_id === tableId); + if (tableConfig) { + queryConfig = { + table_id: tableConfig.table_id, + columns_keys: tableConfig.columns_keys, + query_rows_permission: tableConfig.permissions?.query_rows_permission || {}, + }; + } + } + return this.htmlPageAPI.queryRows(this.options.pageId, tableId, filters, start, limit, queryConfig); + } + listCollaborators() { return this.htmlPageAPI.listCollaborators(); } diff --git a/tests/html-page-api.test.js b/tests/html-page-api.test.js index 079cd28..2a48b5d 100644 --- a/tests/html-page-api.test.js +++ b/tests/html-page-api.test.js @@ -31,6 +31,59 @@ function createApi() { return { api, get, post, put, del }; } +describe('HTMLPageAPI.queryRows', () => { + beforeEach(() => { + jest.clearAllMocks(); + }); + + it('queryRows posts table id and filters to the query endpoint', () => { + const { api, post } = createApi(); + + const response = { data: { metadata: [], results: [] } }; + post.mockReturnValue(response); + + const filters = [{ columnKey: 'phone', value: '13800138000' }]; + const result = api.queryRows('page-1', 'tbl-1', filters, 0, 100); + + expect(result).toEqual(response); + expect(post).toHaveBeenCalledWith( + 'https://example.com/api/v2.1/universal-apps/app-uuid/html-page-rows/query/', + { + page_id: 'page-1', + table_id: 'tbl-1', + filters, + start: 0, + limit: 100, + }, + ); + }); + + it('queryRows sends query_config for ai_agent preview', () => { + const { api, post } = createApi(); + const queryConfig = { + table_id: 'tbl-1', + columns_keys: ['phone'], + query_rows_permission: { + query_columns: [{ column_key: 'phone', enable_fuzzy_query: true }], + }, + }; + + api.queryRows('ai_agent', 'tbl-1', [{ columnKey: 'phone', value: '138' }], 0, 20, queryConfig); + + expect(post).toHaveBeenCalledWith( + 'https://example.com/api/v2.1/universal-apps/app-uuid/html-page-rows/query/', + { + page_id: 'ai_agent', + table_id: 'tbl-1', + filters: [{ columnKey: 'phone', value: '138' }], + start: 0, + limit: 20, + query_config: queryConfig, + }, + ); + }); +}); + describe('HTMLPageAPI.listRows', () => { beforeEach(() => { jest.clearAllMocks(); diff --git a/tests/sdk-init.test.js b/tests/sdk-init.test.js index 82263ff..8c271de 100644 --- a/tests/sdk-init.test.js +++ b/tests/sdk-init.test.js @@ -24,6 +24,7 @@ jest.mock('../src/iframe-adapter', () => ({ GET_ACCESS_TOKEN: 'get_access_token', GET_APP_UUID: 'get_app_uuid', GET_PAGE_ID: 'get_page_id', + GET_QUERY_TABLE_CONFIGS: 'get_query_table_configs', }, })); @@ -78,4 +79,21 @@ describe('HTMLPageSDK.init', () => { expect(sdk.options.pageId).toBe('page-1'); expect(sdk.options.accountToken).toBe('account-token'); }); + + it('loads query table configs for ai_agent preview', async () => { + const queryTableConfigs = [{ table_id: 'REW7', columns_keys: ['0000'] }]; + mockRequest + .mockResolvedValueOnce('https://example.com') + .mockResolvedValueOnce('app-uuid') + .mockResolvedValueOnce('ai_agent') + .mockResolvedValueOnce(queryTableConfigs) + .mockResolvedValueOnce('access-token'); + + const sdk = new HTMLPageSDK(); + await sdk.init(); + + expect(mockRequest).toHaveBeenNthCalledWith(4, 'get_query_table_configs'); + expect(mockRequest).toHaveBeenNthCalledWith(5, 'get_access_token'); + expect(sdk.options.queryTableConfigs).toEqual(queryTableConfigs); + }); }); diff --git a/tests/sdk.test.js b/tests/sdk.test.js index 4a671a5..84d5096 100644 --- a/tests/sdk.test.js +++ b/tests/sdk.test.js @@ -1,6 +1,7 @@ import { HTMLPageSDK } from '../src/sdk'; const mockListRows = jest.fn(); +const mockQueryRows = jest.fn(); const mockListCollaborators = jest.fn(); const mockResolveUsers = jest.fn(); const mockAddRow = jest.fn(); @@ -19,6 +20,7 @@ jest.mock('../src/iframe-adapter', () => ({ GET_ACCESS_TOKEN: 'get_access_token', GET_APP_UUID: 'get_app_uuid', GET_PAGE_ID: 'get_page_id', + GET_QUERY_TABLE_CONFIGS: 'get_query_table_configs', }, })); @@ -58,6 +60,46 @@ describe('rows', () => { expect(mockListRows).toHaveBeenCalledWith('page-1', 'TableName', 0, 100); }); + it('query rows by table id', () => { + const sdk = new HTMLPageSDK({ pageId: 'page-1' }); + sdk.htmlPageAPI = { queryRows: mockQueryRows }; + + const filters = [{ columnKey: '0000', value: 'TEST2026070001' }]; + sdk.queryRows({ tableId: 'REW7', filters }); + + expect(mockQueryRows).toHaveBeenCalledWith('page-1', 'REW7', filters, undefined, undefined, undefined); + }); + + it('query rows includes the configured table query settings for ai_agent preview', () => { + const queryConfig = { + table_id: 'REW7', + columns_keys: ['0000', 'wbyd'], + permissions: { + query_rows_permission: { + query_columns: [{ column_key: '0000', enable_fuzzy_query: true, case_sensitive: false }], + }, + }, + }; + const sdk = new HTMLPageSDK({ pageId: 'ai_agent', queryTableConfigs: [queryConfig] }); + sdk.htmlPageAPI = { queryRows: mockQueryRows }; + + const filters = [{ columnKey: '0000', value: '202607' }]; + sdk.queryRows({ tableId: 'REW7', filters }); + + expect(mockQueryRows).toHaveBeenCalledWith( + 'ai_agent', + 'REW7', + filters, + undefined, + undefined, + { + table_id: 'REW7', + columns_keys: ['0000', 'wbyd'], + query_rows_permission: queryConfig.permissions.query_rows_permission, + }, + ); + }); + it('list collaborators', () => { const sdk = new HTMLPageSDK({ pageId: 'page-1' }); sdk.htmlPageAPI = { listCollaborators: mockListCollaborators }; From e92c53a29a798af133229f904f64ba3c467710b5 Mon Sep 17 00:00:00 2001 From: zwfxxxxx Date: Sat, 8 Aug 2026 12:34:50 +0800 Subject: [PATCH 2/4] support table permissions in AI page previews --- src/apis/html-page-api.js | 36 ++++++++++++---- src/iframe-adapter.js | 2 +- src/sdk.js | 51 +++++++++++++---------- tests/html-page-api.test.js | 83 +++++++++++++++++++++++++++++++++---- tests/sdk-init.test.js | 12 +++--- tests/sdk.test.js | 72 ++++++++++++++++++++++++++------ 6 files changed, 199 insertions(+), 57 deletions(-) diff --git a/src/apis/html-page-api.js b/src/apis/html-page-api.js index 42f56e2..d230e5d 100644 --- a/src/apis/html-page-api.js +++ b/src/apis/html-page-api.js @@ -52,17 +52,20 @@ class HTMLPageAPI { return this.req.put(url, data, { headers: { 'Content-Type': 'application/json' } }); } - listRows(page_id, table_name, start, limit) { + listRows(page_id, table_name, start, limit, preview_table_config) { const url = `${this.server}api/v2.1/universal-apps/${this.appUuid}/html-page-rows/`; const params = { page_id, table_name, start, limit }; + if (preview_table_config && typeof preview_table_config === 'object') { + params.preview_table_config = JSON.stringify(preview_table_config); + } return this.req.get(url, { params }); } - queryRows(page_id, table_id, filters, start, limit, query_config) { + queryRows(page_id, table_id, filters, start, limit, preview_table_config) { const url = `${this.server}api/v2.1/universal-apps/${this.appUuid}/html-page-rows/query/`; const data = { page_id, table_id, filters, start, limit }; - if (query_config && typeof query_config === 'object') { - data.query_config = query_config; + if (preview_table_config && typeof preview_table_config === 'object') { + data.preview_table_config = preview_table_config; } return this.req.post(url, data); } @@ -78,33 +81,48 @@ class HTMLPageAPI { return this.req.post(url, data); } - addRow(page_id, table_name, row_data) { + addRow(page_id, table_name, row_data, preview_table_config) { const url = `${this.server}api/v2.1/universal-apps/${this.appUuid}/html-page-rows/`; const data = { page_id, table_name, row_data }; + if (preview_table_config && typeof preview_table_config === 'object') { + data.preview_table_config = preview_table_config; + } return this.req.post(url, data); } - addRows(page_id, table_name, rows_data) { + addRows(page_id, table_name, rows_data, preview_table_config) { const url = `${this.server}api/v2.1/universal-apps/${this.appUuid}/html-page-rows/batch/`; const data = { page_id, table_name, rows_data }; + if (preview_table_config && typeof preview_table_config === 'object') { + data.preview_table_config = preview_table_config; + } return this.req.post(url, data); } - updateRow(page_id, table_name, row_id, row_data) { + updateRow(page_id, table_name, row_id, row_data, preview_table_config) { const url = `${this.server}api/v2.1/universal-apps/${this.appUuid}/html-page-rows/`; const data = { page_id, table_name, row_id, row_data }; + if (preview_table_config && typeof preview_table_config === 'object') { + data.preview_table_config = preview_table_config; + } return this._sendPut(url, data); } - updateRows(page_id, table_name, rows_data) { + updateRows(page_id, table_name, rows_data, preview_table_config) { const url = `${this.server}api/v2.1/universal-apps/${this.appUuid}/html-page-rows/batch/`; const data = { page_id, table_name, rows_data }; + if (preview_table_config && typeof preview_table_config === 'object') { + data.preview_table_config = preview_table_config; + } return this._sendPut(url, data); } - deleteRows(page_id, table_name, rows_ids) { + deleteRows(page_id, table_name, rows_ids, preview_table_config) { const url = `${this.server}api/v2.1/universal-apps/${this.appUuid}/html-page-rows/`; const data = { page_id, table_name, rows_ids }; + if (preview_table_config && typeof preview_table_config === 'object') { + data.preview_table_config = preview_table_config; + } return this._sendDelete(url, data); } diff --git a/src/iframe-adapter.js b/src/iframe-adapter.js index 0ac76c8..1a524ae 100644 --- a/src/iframe-adapter.js +++ b/src/iframe-adapter.js @@ -10,7 +10,7 @@ export const POST_MESSAGE_REQUEST_TYPE = { GET_ACCESS_TOKEN: 'get_access_token', GET_APP_UUID: 'get_app_uuid', GET_PAGE_ID: 'get_page_id', - GET_QUERY_TABLE_CONFIGS: 'get_query_table_configs', + GET_PREVIEW_TABLE_CONFIGS: 'get_preview_table_configs', }; const WINDOW_EVENT_SOURCE_TYPE = { diff --git a/src/sdk.js b/src/sdk.js index 7980c47..0e5c67d 100644 --- a/src/sdk.js +++ b/src/sdk.js @@ -21,9 +21,9 @@ export class HTMLPageSDK { if (!this.options.pageId) { this.options.pageId = await this.iframeAdapter.request(POST_MESSAGE_REQUEST_TYPE.GET_PAGE_ID); } - if (this.options.pageId === 'ai_agent' && !Array.isArray(this.options.queryTableConfigs)) { - const queryTableConfigs = await this.iframeAdapter.request(POST_MESSAGE_REQUEST_TYPE.GET_QUERY_TABLE_CONFIGS); - this.options.queryTableConfigs = Array.isArray(queryTableConfigs) ? queryTableConfigs : []; + if (this.options.pageId === 'ai_agent' && !Array.isArray(this.options.previewTableConfigs)) { + const previewTableConfigs = await this.iframeAdapter.request(POST_MESSAGE_REQUEST_TYPE.GET_PREVIEW_TABLE_CONFIGS); + this.options.previewTableConfigs = Array.isArray(previewTableConfigs) ? previewTableConfigs : []; } if (this.options.accountToken) { // dev: try to get access-token via accountToken @@ -39,22 +39,26 @@ export class HTMLPageSDK { } listRows({ tableName, start, limit }) { - return this.htmlPageAPI.listRows(this.options.pageId, tableName, start, limit); + const previewTableConfig = this._getPreviewTableConfig({ tableName }); + return this.htmlPageAPI.listRows(this.options.pageId, tableName, start, limit, previewTableConfig); } queryRows({ tableId, filters, start, limit }) { - let queryConfig; - if (this.options.pageId === 'ai_agent' && tableId && Array.isArray(this.options.queryTableConfigs)) { - const tableConfig = this.options.queryTableConfigs.find(config => config?.table_id === tableId); - if (tableConfig) { - queryConfig = { - table_id: tableConfig.table_id, - columns_keys: tableConfig.columns_keys, - query_rows_permission: tableConfig.permissions?.query_rows_permission || {}, - }; - } - } - return this.htmlPageAPI.queryRows(this.options.pageId, tableId, filters, start, limit, queryConfig); + const previewTableConfig = this._getPreviewTableConfig({ tableId }); + return this.htmlPageAPI.queryRows(this.options.pageId, tableId, filters, start, limit, previewTableConfig); + } + + _getPreviewTableConfig({ tableId, tableName }) { + if (this.options.pageId !== 'ai_agent' || !Array.isArray(this.options.previewTableConfigs)) return undefined; + const tableConfig = this.options.previewTableConfigs.find(config => { + if (tableId) return config?.table_id === tableId; + return tableName && config?.table_name === tableName; + }); + if (!tableConfig) return undefined; + return { + table_id: tableConfig.table_id, + permissions: { ...(tableConfig.permissions || {}) }, + }; } listCollaborators() { @@ -66,11 +70,13 @@ export class HTMLPageSDK { } addRow({ tableName, rowData }) { - return this.htmlPageAPI.addRow(this.options.pageId, tableName, rowData); + const previewTableConfig = this._getPreviewTableConfig({ tableName }); + return this.htmlPageAPI.addRow(this.options.pageId, tableName, rowData, previewTableConfig); } updateRow({ tableName, rowId, rowData }) { - return this.htmlPageAPI.updateRow(this.options.pageId, tableName, rowId, rowData); + const previewTableConfig = this._getPreviewTableConfig({ tableName }); + return this.htmlPageAPI.updateRow(this.options.pageId, tableName, rowId, rowData, previewTableConfig); } deleteRow({ tableName, rowId }) { @@ -79,15 +85,18 @@ export class HTMLPageSDK { } batchAddRows({ tableName, rowsData }) { - return this.htmlPageAPI.addRows(this.options.pageId, tableName, rowsData); + const previewTableConfig = this._getPreviewTableConfig({ tableName }); + return this.htmlPageAPI.addRows(this.options.pageId, tableName, rowsData, previewTableConfig); } batchUpdateRows({ tableName, rowsData }) { - return this.htmlPageAPI.updateRows(this.options.pageId, tableName, rowsData); + const previewTableConfig = this._getPreviewTableConfig({ tableName }); + return this.htmlPageAPI.updateRows(this.options.pageId, tableName, rowsData, previewTableConfig); } batchDeleteRows({ tableName, rowsIds }) { - return this.htmlPageAPI.deleteRows(this.options.pageId, tableName, rowsIds); + const previewTableConfig = this._getPreviewTableConfig({ tableName }); + return this.htmlPageAPI.deleteRows(this.options.pageId, tableName, rowsIds, previewTableConfig); } uploadFile({ file }) { diff --git a/tests/html-page-api.test.js b/tests/html-page-api.test.js index 2a48b5d..6ca6e54 100644 --- a/tests/html-page-api.test.js +++ b/tests/html-page-api.test.js @@ -58,17 +58,20 @@ describe('HTMLPageAPI.queryRows', () => { ); }); - it('queryRows sends query_config for ai_agent preview', () => { + it('queryRows sends preview_table_config for ai_agent preview', () => { const { api, post } = createApi(); - const queryConfig = { + const previewTableConfig = { table_id: 'tbl-1', - columns_keys: ['phone'], - query_rows_permission: { - query_columns: [{ column_key: 'phone', enable_fuzzy_query: true }], + permissions: { + query_rows_permission: { + enabled: true, + columns_keys: ['phone'], + query_columns: [{ column_key: 'phone', enable_fuzzy_query: true }], + }, }, }; - api.queryRows('ai_agent', 'tbl-1', [{ columnKey: 'phone', value: '138' }], 0, 20, queryConfig); + api.queryRows('ai_agent', 'tbl-1', [{ columnKey: 'phone', value: '138' }], 0, 20, previewTableConfig); expect(post).toHaveBeenCalledWith( 'https://example.com/api/v2.1/universal-apps/app-uuid/html-page-rows/query/', @@ -78,7 +81,7 @@ describe('HTMLPageAPI.queryRows', () => { filters: [{ columnKey: 'phone', value: '138' }], start: 0, limit: 20, - query_config: queryConfig, + preview_table_config: previewTableConfig, }, ); }); @@ -148,6 +151,26 @@ describe('HTMLPageAPI.listRows', () => { }, ); }); + + it('listRows serializes preview_table_config', () => { + const { api, get } = createApi(); + const previewTableConfig = { table_id: 'tbl-1', permissions: {} }; + + api.listRows('ai_agent', 'TableName', 0, 100, previewTableConfig); + + expect(get).toHaveBeenCalledWith( + 'https://example.com/api/v2.1/universal-apps/app-uuid/html-page-rows/', + { + params: { + page_id: 'ai_agent', + table_name: 'TableName', + start: 0, + limit: 100, + preview_table_config: JSON.stringify(previewTableConfig), + }, + }, + ); + }); }); describe('HTMLPageAPI.listCollaborators', () => { @@ -324,6 +347,52 @@ describe('HTMLPageAPI.deleteRows(s)', () => { }, ); }); + + it('write APIs send preview_table_config', () => { + const { api, post, put, del } = createApi(); + const previewTableConfig = { table_id: 'tbl-1', permissions: {} }; + + api.addRow('ai_agent', 'TableName', { Name: 'A' }, previewTableConfig); + api.addRows('ai_agent', 'TableName', [{ Name: 'B' }], previewTableConfig); + api.updateRow('ai_agent', 'TableName', 'row-1', { Name: 'C' }, previewTableConfig); + api.updateRows('ai_agent', 'TableName', [{ row_id: 'row-1', row: { Name: 'D' } }], previewTableConfig); + api.deleteRows('ai_agent', 'TableName', ['row-1'], previewTableConfig); + + expect(post).toHaveBeenNthCalledWith(1, expect.any(String), { + page_id: 'ai_agent', + table_name: 'TableName', + row_data: { Name: 'A' }, + preview_table_config: previewTableConfig, + }); + expect(post).toHaveBeenNthCalledWith(2, expect.any(String), { + page_id: 'ai_agent', + table_name: 'TableName', + rows_data: [{ Name: 'B' }], + preview_table_config: previewTableConfig, + }); + expect(put).toHaveBeenNthCalledWith(1, expect.any(String), { + page_id: 'ai_agent', + table_name: 'TableName', + row_id: 'row-1', + row_data: { Name: 'C' }, + preview_table_config: previewTableConfig, + }, expect.any(Object)); + expect(put).toHaveBeenNthCalledWith(2, expect.any(String), { + page_id: 'ai_agent', + table_name: 'TableName', + rows_data: [{ row_id: 'row-1', row: { Name: 'D' } }], + preview_table_config: previewTableConfig, + }, expect.any(Object)); + expect(del).toHaveBeenCalledWith(expect.any(String), { + headers: { 'Content-Type': 'application/json' }, + data: { + page_id: 'ai_agent', + table_name: 'TableName', + rows_ids: ['row-1'], + preview_table_config: previewTableConfig, + }, + }); + }); }); describe('HTMLPageAPI.upload', () => { diff --git a/tests/sdk-init.test.js b/tests/sdk-init.test.js index 8c271de..a0b347f 100644 --- a/tests/sdk-init.test.js +++ b/tests/sdk-init.test.js @@ -24,7 +24,7 @@ jest.mock('../src/iframe-adapter', () => ({ GET_ACCESS_TOKEN: 'get_access_token', GET_APP_UUID: 'get_app_uuid', GET_PAGE_ID: 'get_page_id', - GET_QUERY_TABLE_CONFIGS: 'get_query_table_configs', + GET_PREVIEW_TABLE_CONFIGS: 'get_preview_table_configs', }, })); @@ -80,20 +80,20 @@ describe('HTMLPageSDK.init', () => { expect(sdk.options.accountToken).toBe('account-token'); }); - it('loads query table configs for ai_agent preview', async () => { - const queryTableConfigs = [{ table_id: 'REW7', columns_keys: ['0000'] }]; + it('loads table permission configs for ai_agent preview', async () => { + const previewTableConfigs = [{ table_id: 'REW7', permissions: {} }]; mockRequest .mockResolvedValueOnce('https://example.com') .mockResolvedValueOnce('app-uuid') .mockResolvedValueOnce('ai_agent') - .mockResolvedValueOnce(queryTableConfigs) + .mockResolvedValueOnce(previewTableConfigs) .mockResolvedValueOnce('access-token'); const sdk = new HTMLPageSDK(); await sdk.init(); - expect(mockRequest).toHaveBeenNthCalledWith(4, 'get_query_table_configs'); + expect(mockRequest).toHaveBeenNthCalledWith(4, 'get_preview_table_configs'); expect(mockRequest).toHaveBeenNthCalledWith(5, 'get_access_token'); - expect(sdk.options.queryTableConfigs).toEqual(queryTableConfigs); + expect(sdk.options.previewTableConfigs).toEqual(previewTableConfigs); }); }); diff --git a/tests/sdk.test.js b/tests/sdk.test.js index 84d5096..9bcd3c9 100644 --- a/tests/sdk.test.js +++ b/tests/sdk.test.js @@ -20,7 +20,7 @@ jest.mock('../src/iframe-adapter', () => ({ GET_ACCESS_TOKEN: 'get_access_token', GET_APP_UUID: 'get_app_uuid', GET_PAGE_ID: 'get_page_id', - GET_QUERY_TABLE_CONFIGS: 'get_query_table_configs', + GET_PREVIEW_TABLE_CONFIGS: 'get_preview_table_configs', }, })); @@ -57,7 +57,7 @@ describe('rows', () => { }); expect(result).toBe(response); - expect(mockListRows).toHaveBeenCalledWith('page-1', 'TableName', 0, 100); + expect(mockListRows).toHaveBeenCalledWith('page-1', 'TableName', 0, 100, undefined); }); it('query rows by table id', () => { @@ -70,17 +70,19 @@ describe('rows', () => { expect(mockQueryRows).toHaveBeenCalledWith('page-1', 'REW7', filters, undefined, undefined, undefined); }); - it('query rows includes the configured table query settings for ai_agent preview', () => { - const queryConfig = { + it('query rows includes the configured table permissions for ai_agent preview', () => { + const previewTableConfig = { table_id: 'REW7', - columns_keys: ['0000', 'wbyd'], + table_name: 'Order', permissions: { query_rows_permission: { + enabled: true, + columns_keys: ['0000', 'wbyd'], query_columns: [{ column_key: '0000', enable_fuzzy_query: true, case_sensitive: false }], }, }, }; - const sdk = new HTMLPageSDK({ pageId: 'ai_agent', queryTableConfigs: [queryConfig] }); + const sdk = new HTMLPageSDK({ pageId: 'ai_agent', previewTableConfigs: [previewTableConfig] }); sdk.htmlPageAPI = { queryRows: mockQueryRows }; const filters = [{ columnKey: '0000', value: '202607' }]; @@ -94,12 +96,56 @@ describe('rows', () => { undefined, { table_id: 'REW7', - columns_keys: ['0000', 'wbyd'], - query_rows_permission: queryConfig.permissions.query_rows_permission, + permissions: previewTableConfig.permissions, }, ); }); + it('row APIs include the matching table permissions for ai_agent preview', () => { + const previewTableConfig = { + table_id: 'REW7', + table_name: 'Order', + permissions: { + view_rows_permission: { enabled: true, columns_keys: ['0000'] }, + add_rows_permission: { enabled: true, columns_keys: ['0000'] }, + edit_rows_permission: { enabled: true, columns_keys: ['0000'] }, + delete_rows_permission: { enabled: true }, + }, + }; + const expectedConfig = { + table_id: 'REW7', + permissions: previewTableConfig.permissions, + }; + const sdk = new HTMLPageSDK({ pageId: 'ai_agent', previewTableConfigs: [previewTableConfig] }); + sdk.htmlPageAPI = { + listRows: mockListRows, + addRow: mockAddRow, + updateRow: mockUpdateRow, + deleteRows: mockDeleteRows, + addRows: mockAddRows, + updateRows: mockUpdateRows, + }; + + sdk.listRows({ tableName: 'Order' }); + sdk.addRow({ tableName: 'Order', rowData: { OrderNumber: '001' } }); + sdk.updateRow({ tableName: 'Order', rowId: 'row-1', rowData: { OrderNumber: '002' } }); + sdk.batchAddRows({ tableName: 'Order', rowsData: [{ OrderNumber: '003' }] }); + sdk.batchUpdateRows({ tableName: 'Order', rowsData: [{ row_id: 'row-1', row: { OrderNumber: '004' } }] }); + sdk.batchDeleteRows({ tableName: 'Order', rowsIds: ['row-1'] }); + + expect(mockListRows).toHaveBeenCalledWith('ai_agent', 'Order', undefined, undefined, expectedConfig); + expect(mockAddRow).toHaveBeenCalledWith('ai_agent', 'Order', { OrderNumber: '001' }, expectedConfig); + expect(mockUpdateRow).toHaveBeenCalledWith('ai_agent', 'Order', 'row-1', { OrderNumber: '002' }, expectedConfig); + expect(mockAddRows).toHaveBeenCalledWith('ai_agent', 'Order', [{ OrderNumber: '003' }], expectedConfig); + expect(mockUpdateRows).toHaveBeenCalledWith( + 'ai_agent', + 'Order', + [{ row_id: 'row-1', row: { OrderNumber: '004' } }], + expectedConfig, + ); + expect(mockDeleteRows).toHaveBeenCalledWith('ai_agent', 'Order', ['row-1'], expectedConfig); + }); + it('list collaborators', () => { const sdk = new HTMLPageSDK({ pageId: 'page-1' }); sdk.htmlPageAPI = { listCollaborators: mockListCollaborators }; @@ -163,11 +209,11 @@ describe('rows', () => { expect(sdk.batchUpdateRows({ tableName: 'TableName', rowsData: [{ row_id: 'row-1', Name: 'Jane' }] })).toEqual(updateRowsResponse); expect(sdk.batchDeleteRows({ tableName: 'TableName', rowsIds: ['row-1'] })).toEqual(deleteRowsResponse); - expect(mockAddRow).toHaveBeenCalledWith('page-1', 'TableName', { Name: 'John' }); - expect(mockUpdateRow).toHaveBeenCalledWith('page-1', 'TableName', 'row-1', { Name: 'Jane' }); - expect(mockDeleteRows).toHaveBeenCalledWith('page-1', 'TableName', ['row-1']); - expect(mockAddRows).toHaveBeenCalledWith('page-1', 'TableName', [{ Name: 'John' }]); - expect(mockUpdateRows).toHaveBeenCalledWith('page-1', 'TableName', [{ row_id: 'row-1', Name: 'Jane' }]); + expect(mockAddRow).toHaveBeenCalledWith('page-1', 'TableName', { Name: 'John' }, undefined); + expect(mockUpdateRow).toHaveBeenCalledWith('page-1', 'TableName', 'row-1', { Name: 'Jane' }, undefined); + expect(mockDeleteRows).toHaveBeenCalledWith('page-1', 'TableName', ['row-1'], undefined); + expect(mockAddRows).toHaveBeenCalledWith('page-1', 'TableName', [{ Name: 'John' }], undefined); + expect(mockUpdateRows).toHaveBeenCalledWith('page-1', 'TableName', [{ row_id: 'row-1', Name: 'Jane' }], undefined); expect(mockDeleteRows).toHaveBeenCalledTimes(2); }); }); From a567963af3b31a27452cb6c2f6fbe33a2d2cae0e Mon Sep 17 00:00:00 2001 From: zwfxxxxx Date: Tue, 18 Aug 2026 23:47:10 +0800 Subject: [PATCH 3/4] update queryRows param --- src/apis/html-page-api.js | 4 ++-- src/sdk.js | 13 +++++-------- tests/html-page-api.test.js | 16 ++++++++-------- tests/sdk.test.js | 14 +++++++------- 4 files changed, 22 insertions(+), 25 deletions(-) diff --git a/src/apis/html-page-api.js b/src/apis/html-page-api.js index d230e5d..c3643b5 100644 --- a/src/apis/html-page-api.js +++ b/src/apis/html-page-api.js @@ -61,9 +61,9 @@ class HTMLPageAPI { return this.req.get(url, { params }); } - queryRows(page_id, table_id, filters, start, limit, preview_table_config) { + queryRows(page_id, table_name, conditions, start, limit, preview_table_config) { const url = `${this.server}api/v2.1/universal-apps/${this.appUuid}/html-page-rows/query/`; - const data = { page_id, table_id, filters, start, limit }; + const data = { page_id, table_name, conditions, start, limit }; if (preview_table_config && typeof preview_table_config === 'object') { data.preview_table_config = preview_table_config; } diff --git a/src/sdk.js b/src/sdk.js index 0e5c67d..b46cc18 100644 --- a/src/sdk.js +++ b/src/sdk.js @@ -43,17 +43,14 @@ export class HTMLPageSDK { return this.htmlPageAPI.listRows(this.options.pageId, tableName, start, limit, previewTableConfig); } - queryRows({ tableId, filters, start, limit }) { - const previewTableConfig = this._getPreviewTableConfig({ tableId }); - return this.htmlPageAPI.queryRows(this.options.pageId, tableId, filters, start, limit, previewTableConfig); + queryRows({ tableName, conditions, start, limit }) { + const previewTableConfig = this._getPreviewTableConfig({ tableName }); + return this.htmlPageAPI.queryRows(this.options.pageId, tableName, conditions, start, limit, previewTableConfig); } - _getPreviewTableConfig({ tableId, tableName }) { + _getPreviewTableConfig({ tableName }) { if (this.options.pageId !== 'ai_agent' || !Array.isArray(this.options.previewTableConfigs)) return undefined; - const tableConfig = this.options.previewTableConfigs.find(config => { - if (tableId) return config?.table_id === tableId; - return tableName && config?.table_name === tableName; - }); + const tableConfig = this.options.previewTableConfigs.find(config => tableName && config?.table_name === tableName); if (!tableConfig) return undefined; return { table_id: tableConfig.table_id, diff --git a/tests/html-page-api.test.js b/tests/html-page-api.test.js index 6ca6e54..9bb4a51 100644 --- a/tests/html-page-api.test.js +++ b/tests/html-page-api.test.js @@ -36,22 +36,22 @@ describe('HTMLPageAPI.queryRows', () => { jest.clearAllMocks(); }); - it('queryRows posts table id and filters to the query endpoint', () => { + it('queryRows posts table name and conditions to the query endpoint', () => { const { api, post } = createApi(); const response = { data: { metadata: [], results: [] } }; post.mockReturnValue(response); - const filters = [{ columnKey: 'phone', value: '13800138000' }]; - const result = api.queryRows('page-1', 'tbl-1', filters, 0, 100); + const conditions = [{ columnKey: 'phone', value: '13800138000' }]; + const result = api.queryRows('page-1', 'Orders', conditions, 0, 100); expect(result).toEqual(response); expect(post).toHaveBeenCalledWith( 'https://example.com/api/v2.1/universal-apps/app-uuid/html-page-rows/query/', { page_id: 'page-1', - table_id: 'tbl-1', - filters, + table_name: 'Orders', + conditions, start: 0, limit: 100, }, @@ -71,14 +71,14 @@ describe('HTMLPageAPI.queryRows', () => { }, }; - api.queryRows('ai_agent', 'tbl-1', [{ columnKey: 'phone', value: '138' }], 0, 20, previewTableConfig); + api.queryRows('ai_agent', 'Orders', [{ columnKey: 'phone', value: '138' }], 0, 20, previewTableConfig); expect(post).toHaveBeenCalledWith( 'https://example.com/api/v2.1/universal-apps/app-uuid/html-page-rows/query/', { page_id: 'ai_agent', - table_id: 'tbl-1', - filters: [{ columnKey: 'phone', value: '138' }], + table_name: 'Orders', + conditions: [{ columnKey: 'phone', value: '138' }], start: 0, limit: 20, preview_table_config: previewTableConfig, diff --git a/tests/sdk.test.js b/tests/sdk.test.js index 9bcd3c9..cb39c3e 100644 --- a/tests/sdk.test.js +++ b/tests/sdk.test.js @@ -64,10 +64,10 @@ describe('rows', () => { const sdk = new HTMLPageSDK({ pageId: 'page-1' }); sdk.htmlPageAPI = { queryRows: mockQueryRows }; - const filters = [{ columnKey: '0000', value: 'TEST2026070001' }]; - sdk.queryRows({ tableId: 'REW7', filters }); + const conditions = [{ columnKey: '0000', value: 'TEST2026070001' }]; + sdk.queryRows({ tableName: 'Order', conditions }); - expect(mockQueryRows).toHaveBeenCalledWith('page-1', 'REW7', filters, undefined, undefined, undefined); + expect(mockQueryRows).toHaveBeenCalledWith('page-1', 'Order', conditions, undefined, undefined, undefined); }); it('query rows includes the configured table permissions for ai_agent preview', () => { @@ -85,13 +85,13 @@ describe('rows', () => { const sdk = new HTMLPageSDK({ pageId: 'ai_agent', previewTableConfigs: [previewTableConfig] }); sdk.htmlPageAPI = { queryRows: mockQueryRows }; - const filters = [{ columnKey: '0000', value: '202607' }]; - sdk.queryRows({ tableId: 'REW7', filters }); + const conditions = [{ columnKey: '0000', value: '202607' }]; + sdk.queryRows({ tableName: 'Order', conditions }); expect(mockQueryRows).toHaveBeenCalledWith( 'ai_agent', - 'REW7', - filters, + 'Order', + conditions, undefined, undefined, { From c4c558a667c590898121172bd47dea6549979476 Mon Sep 17 00:00:00 2001 From: zwfxxxxx Date: Wed, 19 Aug 2026 00:21:20 +0800 Subject: [PATCH 4/4] opt queryRows sdk test --- tests/html-page-api.test.js | 6 +++--- tests/sdk.test.js | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/html-page-api.test.js b/tests/html-page-api.test.js index 9bb4a51..1e52332 100644 --- a/tests/html-page-api.test.js +++ b/tests/html-page-api.test.js @@ -42,7 +42,7 @@ describe('HTMLPageAPI.queryRows', () => { const response = { data: { metadata: [], results: [] } }; post.mockReturnValue(response); - const conditions = [{ columnKey: 'phone', value: '13800138000' }]; + const conditions = [{ columnName: 'Phone', value: '13800138000' }]; const result = api.queryRows('page-1', 'Orders', conditions, 0, 100); expect(result).toEqual(response); @@ -71,14 +71,14 @@ describe('HTMLPageAPI.queryRows', () => { }, }; - api.queryRows('ai_agent', 'Orders', [{ columnKey: 'phone', value: '138' }], 0, 20, previewTableConfig); + api.queryRows('ai_agent', 'Orders', [{ columnName: 'Phone', value: '138' }], 0, 20, previewTableConfig); expect(post).toHaveBeenCalledWith( 'https://example.com/api/v2.1/universal-apps/app-uuid/html-page-rows/query/', { page_id: 'ai_agent', table_name: 'Orders', - conditions: [{ columnKey: 'phone', value: '138' }], + conditions: [{ columnName: 'Phone', value: '138' }], start: 0, limit: 20, preview_table_config: previewTableConfig, diff --git a/tests/sdk.test.js b/tests/sdk.test.js index cb39c3e..3d5bd88 100644 --- a/tests/sdk.test.js +++ b/tests/sdk.test.js @@ -60,11 +60,11 @@ describe('rows', () => { expect(mockListRows).toHaveBeenCalledWith('page-1', 'TableName', 0, 100, undefined); }); - it('query rows by table id', () => { + it('query rows by table and column names', () => { const sdk = new HTMLPageSDK({ pageId: 'page-1' }); sdk.htmlPageAPI = { queryRows: mockQueryRows }; - const conditions = [{ columnKey: '0000', value: 'TEST2026070001' }]; + const conditions = [{ columnName: 'Order Number', value: 'TEST2026070001' }]; sdk.queryRows({ tableName: 'Order', conditions }); expect(mockQueryRows).toHaveBeenCalledWith('page-1', 'Order', conditions, undefined, undefined, undefined); @@ -85,7 +85,7 @@ describe('rows', () => { const sdk = new HTMLPageSDK({ pageId: 'ai_agent', previewTableConfigs: [previewTableConfig] }); sdk.htmlPageAPI = { queryRows: mockQueryRows }; - const conditions = [{ columnKey: '0000', value: '202607' }]; + const conditions = [{ columnName: 'Order Number', value: '202607' }]; sdk.queryRows({ tableName: 'Order', conditions }); expect(mockQueryRows).toHaveBeenCalledWith(