From 03d273a7a8e2759dde3a455c7548ddcc35d69e3b Mon Sep 17 00:00:00 2001 From: Bieber Date: Mon, 2 Sep 2024 14:13:38 +0700 Subject: [PATCH] feat: add configApi method (#874) * feat: add configApi method * chore: publish 1.4.0 release * test: skip export in sqlite --- apps/nestjs-backend/package.json | 2 +- .../test/table-export.e2e-spec.ts | 119 +++++++++--------- apps/nextjs-app/package.json | 2 +- package.json | 2 +- packages/common-i18n/package.json | 2 +- packages/core/package.json | 2 +- packages/db-main-prisma/package.json | 2 +- packages/eslint-config-bases/package.json | 2 +- packages/icons/package.json | 2 +- packages/openapi/package.json | 2 +- packages/openapi/src/axios.ts | 48 ++++++- packages/sdk/package.json | 2 +- packages/ui-lib/package.json | 2 +- 13 files changed, 119 insertions(+), 70 deletions(-) diff --git a/apps/nestjs-backend/package.json b/apps/nestjs-backend/package.json index eda76bb62..efc5b5ceb 100644 --- a/apps/nestjs-backend/package.json +++ b/apps/nestjs-backend/package.json @@ -1,6 +1,6 @@ { "name": "@teable/backend", - "version": "1.3.2", + "version": "1.4.0", "license": "AGPL-3.0", "private": true, "main": "dist/index.js", diff --git a/apps/nestjs-backend/test/table-export.e2e-spec.ts b/apps/nestjs-backend/test/table-export.e2e-spec.ts index 7e2ea5cdc..4c6d9d307 100644 --- a/apps/nestjs-backend/test/table-export.e2e-spec.ts +++ b/apps/nestjs-backend/test/table-export.e2e-spec.ts @@ -3,7 +3,7 @@ import os from 'node:os'; import path from 'path'; import type { INestApplication } from '@nestjs/common'; import type { IFieldVo } from '@teable/core'; -import { FieldType, Colors, Relationship, ViewType } from '@teable/core'; +import { FieldType, Colors, Relationship, ViewType, DriverClient } from '@teable/core'; import type { INotifyVo } from '@teable/openapi'; import { exportCsvFromTable as apiExportCsvFromTable, @@ -257,70 +257,75 @@ const createRecordsWithLink = async (mainTableId: string, subTableId: string) => }); }; -describe('/export/${tableId} OpenAPI ExportController (e2e) Get csv stream from table (Get) ', () => { - it(`should return a csv stream from table and compatible all fields`, async () => { - const { mainTable, subTable } = await createTables(); - - const exportRes = await apiExportCsvFromTable(mainTable.id); - const disposition = exportRes?.headers[contentDispositionKey]; - const contentType = exportRes?.headers[contentTypeKey]; - const { data: csvData } = exportRes; - - await apiDeleteTable(baseId, mainTable.id); - await apiDeleteTable(baseId, subTable.id); - - expect(disposition).toBe(`attachment; filename=${encodeURIComponent(mainTable.name)}.csv`); - expect(contentType).toBe('text/csv'); - expect(csvData).toBe( - `Text field,Number field,Checkbox field,Select field,Date field,Attachment field,User Field,Link field,Link field from lookups sub_Name,Link field from lookups sub_Number,Link field from lookups sub_Checkbox,Link field from lookups sub_SingleSelect\r\ntxt1,1.00,true,x,2022-11-28,test.txt ${txtFileData.presignedUrl},,Name1,Name1,1.00,true,sub_y\r\ntxt2,,,y,2022-11-28,,test,,,,,\r\n,,true,z,,,,,,,,` - ); - }); +describe.skipIf(globalThis.testConfig.driver === DriverClient.Sqlite)( + '/export/${tableId} OpenAPI ExportController (e2e) Get csv stream from table (Get) ', + () => { + it(`should return a csv stream from table and compatible all fields`, async () => { + const { mainTable, subTable } = await createTables(); + + const exportRes = await apiExportCsvFromTable(mainTable.id); + const disposition = exportRes?.headers[contentDispositionKey]; + const contentType = exportRes?.headers[contentTypeKey]; + const { data: csvData } = exportRes; + + await apiDeleteTable(baseId, mainTable.id); + await apiDeleteTable(baseId, subTable.id); + + expect(disposition).toBe(`attachment; filename=${encodeURIComponent(mainTable.name)}.csv`); + expect(contentType).toBe('text/csv'); + expect(csvData).toBe( + `Text field,Number field,Checkbox field,Select field,Date field,Attachment field,User Field,Link field,Link field from lookups sub_Name,Link field from lookups sub_Number,Link field from lookups sub_Checkbox,Link field from lookups sub_SingleSelect\r\ntxt1,1.00,true,x,2022-11-28,test.txt ${txtFileData.presignedUrl},,Name1,Name1,1.00,true,sub_y\r\ntxt2,,,y,2022-11-28,,test,,,,,\r\n,,true,z,,,,,,,,` + ); + }); - it(`should return a csv stream from table with special character table name`, async () => { - const { mainTable, subTable } = await createTables('测试😄', 'subTable'); + it(`should return a csv stream from table with special character table name`, async () => { + const { mainTable, subTable } = await createTables('测试😄', 'subTable'); - const exportRes = await apiExportCsvFromTable(mainTable.id); - const disposition = exportRes?.headers['content-disposition']; - const contentType = exportRes?.headers['content-type']; - const { data: csvData } = exportRes; + const exportRes = await apiExportCsvFromTable(mainTable.id); + const disposition = exportRes?.headers['content-disposition']; + const contentType = exportRes?.headers['content-type']; + const { data: csvData } = exportRes; - await apiDeleteTable(baseId, mainTable.id); - await apiDeleteTable(baseId, subTable.id); + await apiDeleteTable(baseId, mainTable.id); + await apiDeleteTable(baseId, subTable.id); - expect(disposition).toBe(`attachment; filename=${encodeURIComponent(mainTable.name)}.csv`); - expect(contentType).toBe('text/csv'); - expect(csvData).toBe( - `Text field,Number field,Checkbox field,Select field,Date field,Attachment field,User Field,Link field,Link field from lookups sub_Name,Link field from lookups sub_Number,Link field from lookups sub_Checkbox,Link field from lookups sub_SingleSelect\r\ntxt1,1.00,true,x,2022-11-28,test.txt ${txtFileData.presignedUrl},,Name1,Name1,1.00,true,sub_y\r\ntxt2,,,y,2022-11-28,,test,,,,,\r\n,,true,z,,,,,,,,` - ); - }); + expect(disposition).toBe(`attachment; filename=${encodeURIComponent(mainTable.name)}.csv`); + expect(contentType).toBe('text/csv'); + expect(csvData).toBe( + `Text field,Number field,Checkbox field,Select field,Date field,Attachment field,User Field,Link field,Link field from lookups sub_Name,Link field from lookups sub_Number,Link field from lookups sub_Checkbox,Link field from lookups sub_SingleSelect\r\ntxt1,1.00,true,x,2022-11-28,test.txt ${txtFileData.presignedUrl},,Name1,Name1,1.00,true,sub_y\r\ntxt2,,,y,2022-11-28,,test,,,,,\r\n,,true,z,,,,,,,,` + ); + }); - it(`should return a csv stream from a particular view`, async () => { - const { mainTable, subTable } = await createTables(); + it(`should return a csv stream from a particular view`, async () => { + const { mainTable, subTable } = await createTables(); - const numberField = mainTable?.fields?.find( - (field) => field.name === 'Number field' - ) as IFieldVo; + const numberField = mainTable?.fields?.find( + (field) => field.name === 'Number field' + ) as IFieldVo; - const oldColumnMeta = mainTable?.views?.[0]?.columnMeta; - const view2 = await createView(mainTable.id, { - columnMeta: { - ...oldColumnMeta, - [numberField.id]: { - ...oldColumnMeta?.[numberField.id], - order: 0.5, + const oldColumnMeta = mainTable?.views?.[0]?.columnMeta; + const view2 = await createView(mainTable.id, { + columnMeta: { + ...oldColumnMeta, + [numberField.id]: { + ...oldColumnMeta?.[numberField.id], + order: 0.5, + }, }, - }, - type: ViewType.Grid, - }); + type: ViewType.Grid, + }); - const exportRes = await apiExportCsvFromTable(mainTable.id, view2.id); - const { data: csvData } = exportRes; + const exportRes = await apiExportCsvFromTable(mainTable.id, view2.id); + const { data: csvData } = exportRes; - await apiDeleteTable(baseId, mainTable.id); - await apiDeleteTable(baseId, subTable.id); + console.log('exportRes', csvData); - expect(csvData).toBe( - `Text field,Number field,Checkbox field,Select field,Date field,Attachment field,User Field,Link field,Link field from lookups sub_Name,Link field from lookups sub_Number,Link field from lookups sub_Checkbox,Link field from lookups sub_SingleSelect\r\ntxt1,1.00,true,x,2022-11-28,test.txt ${txtFileData.presignedUrl},,Name1,Name1,1.00,true,sub_y\r\ntxt2,,,y,2022-11-28,,test,,,,,\r\n,,true,z,,,,,,,,` - ); - }); -}); + await apiDeleteTable(baseId, mainTable.id); + await apiDeleteTable(baseId, subTable.id); + + expect(csvData).toBe( + `Text field,Number field,Checkbox field,Select field,Date field,Attachment field,User Field,Link field,Link field from lookups sub_Name,Link field from lookups sub_Number,Link field from lookups sub_Checkbox,Link field from lookups sub_SingleSelect\r\ntxt1,1.00,true,x,2022-11-28,test.txt ${txtFileData.presignedUrl},,Name1,Name1,1.00,true,sub_y\r\ntxt2,,,y,2022-11-28,,test,,,,,\r\n,,true,z,,,,,,,,` + ); + }); + } +); diff --git a/apps/nextjs-app/package.json b/apps/nextjs-app/package.json index c95799f12..e20218183 100644 --- a/apps/nextjs-app/package.json +++ b/apps/nextjs-app/package.json @@ -1,6 +1,6 @@ { "name": "@teable/app", - "version": "1.3.2", + "version": "1.4.0", "license": "AGPL-3.0", "private": true, "main": "main/index.js", diff --git a/package.json b/package.json index 43191db4c..91daf8521 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@teable/teable", - "version": "1.3.2", + "version": "1.4.0", "license": "AGPL-3.0", "private": true, "homepage": "https://github.com/teableio/teable", diff --git a/packages/common-i18n/package.json b/packages/common-i18n/package.json index 06dda19fc..304099c66 100644 --- a/packages/common-i18n/package.json +++ b/packages/common-i18n/package.json @@ -1,6 +1,6 @@ { "name": "@teable/common-i18n", - "version": "1.3.2", + "version": "1.4.0", "license": "MIT", "homepage": "https://github.com/teableio/teable", "private": false, diff --git a/packages/core/package.json b/packages/core/package.json index e2afc9dfd..0c0e905c9 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -1,6 +1,6 @@ { "name": "@teable/core", - "version": "1.3.2", + "version": "1.4.0", "license": "MIT", "homepage": "https://github.com/teableio/teable", "publishConfig": { diff --git a/packages/db-main-prisma/package.json b/packages/db-main-prisma/package.json index 7029e1a59..b667e35b6 100644 --- a/packages/db-main-prisma/package.json +++ b/packages/db-main-prisma/package.json @@ -1,6 +1,6 @@ { "name": "@teable/db-main-prisma", - "version": "1.3.2", + "version": "1.4.0", "license": "MIT", "homepage": "https://github.com/teableio/teable", "private": true, diff --git a/packages/eslint-config-bases/package.json b/packages/eslint-config-bases/package.json index 3fa3e6ca8..a0148061a 100644 --- a/packages/eslint-config-bases/package.json +++ b/packages/eslint-config-bases/package.json @@ -1,6 +1,6 @@ { "name": "@teable/eslint-config-bases", - "version": "1.3.2", + "version": "1.4.0", "license": "MIT", "private": true, "homepage": "https://github.com/teableio/teable", diff --git a/packages/icons/package.json b/packages/icons/package.json index cdb83bd7b..e949e070c 100644 --- a/packages/icons/package.json +++ b/packages/icons/package.json @@ -1,6 +1,6 @@ { "name": "@teable/icons", - "version": "1.3.2", + "version": "1.4.0", "license": "MIT", "homepage": "https://github.com/teableio/teable", "publishConfig": { diff --git a/packages/openapi/package.json b/packages/openapi/package.json index ce78738c9..b241536c1 100644 --- a/packages/openapi/package.json +++ b/packages/openapi/package.json @@ -1,6 +1,6 @@ { "name": "@teable/openapi", - "version": "1.3.2", + "version": "1.4.0", "license": "MIT", "homepage": "https://github.com/teableio/teable", "publishConfig": { diff --git a/packages/openapi/src/axios.ts b/packages/openapi/src/axios.ts index ce259d02e..746e04940 100644 --- a/packages/openapi/src/axios.ts +++ b/packages/openapi/src/axios.ts @@ -1,4 +1,4 @@ -import { HttpError } from '@teable/core'; +import { generateWindowId, HttpError } from '@teable/core'; import axiosInstance from 'axios'; export const createAxios = () => { @@ -20,4 +20,48 @@ export const createAxios = () => { return axios; }; -export const axios = createAxios(); +const axios = createAxios(); + +/** + * Configuration options for the Axios instance. + */ +export interface IAPIRequestConfig { + /** + * API endpoint, defaults to 'https://app.teable.io'. + */ + endpoint?: string; + /** + * Bearer token for authentication. + */ + token: string; + /** + * Enable undo/redo functionality for API calls related to record, field, and view mutations + */ + enableUndoRedo?: boolean; +} + +/** + * Configures the Axios instance with the provided options. + * @param config - Configuration options + */ +export const configApi = (config: IAPIRequestConfig) => { + const { token, enableUndoRedo, endpoint = 'https://app.teable.io' } = config; + if (!token) { + throw new Error( + `token is required, visit ${endpoint}/setting/personal-access-token to get one` + ); + } + + axios.defaults.baseURL = `${endpoint}/api`; + axios.defaults.headers.common['Authorization'] = `Bearer ${token}`; + + // Add windowId for undo/redo functionality if enabled + if (enableUndoRedo) { + const windowId = generateWindowId(); + axios.defaults.headers.common['X-Window-Id'] = windowId; + } + + return axios; +}; + +export { axios }; diff --git a/packages/sdk/package.json b/packages/sdk/package.json index bde4831c8..f09f88d64 100644 --- a/packages/sdk/package.json +++ b/packages/sdk/package.json @@ -1,6 +1,6 @@ { "name": "@teable/sdk", - "version": "1.3.2", + "version": "1.4.0", "license": "MIT", "homepage": "https://github.com/teableio/teable", "publishConfig": { diff --git a/packages/ui-lib/package.json b/packages/ui-lib/package.json index 97d1ff307..3982bd298 100644 --- a/packages/ui-lib/package.json +++ b/packages/ui-lib/package.json @@ -1,6 +1,6 @@ { "name": "@teable/ui-lib", - "version": "1.3.2", + "version": "1.4.0", "license": "MIT", "homepage": "https://github.com/teableio/teable", "publishConfig": {