mirror of
https://github.com/teableio/teable.git
synced 2026-01-20 20:52:53 +08:00
* feat: add chart localization support in multiple languages * feat: add plugin proxy configuration to Next.js app * refactor: improve plugin query for dashboard and plugin panel * refactor: move chart components and add ComponentPluginRender * fix: update translation namespace for YAxisPositionEditor component * fix: adjust column configuration in DashboardGrid for responsive layout * refactor: remove baseQueryRoute and replace baseQuery function calls in e2e tests * Revert "feat: add plugin proxy configuration to Next.js app" This reverts commit 1e9c2dc1e2ba8d36b51290f53d6c882650238f4a. * refactor: clean up global styles by removing unused CSS and updating imports * refactor: remove chart components, API endpoints, and localization files in plugins * fix: cell format in dashboard and plugin panel services * fix: update query parameter in dashboard routing for consistency * refactor: optimize useBaseQueryData with useMemo for performance improvements * fix: can notsee the drop-down menu * feat: auto active panel when plugin creation * feat: enhance DashboardGrid responsiveness with breakpoint handling * refactor: add PluginChartModule and clean up unused query endpoints * refactor: remove unused IBaseQuery imports and clean up service dependencies * refactor: remove unused pluginUserId and avatarPath from chart configuration * refactor: using useMemo for pageParams and parentBridgeMethods * refactor: update parameter names for plugin routes to maintain consistency * test: add end-to-end tests for Plugin and Dashboard chart functionalities
252 lines
7.5 KiB
TypeScript
252 lines
7.5 KiB
TypeScript
import type { INestApplication } from '@nestjs/common';
|
|
import { FieldType } from '@teable/core';
|
|
import type { IBaseQueryVo, ITableFullVo } from '@teable/openapi';
|
|
import {
|
|
createPluginPanel,
|
|
createDashboard,
|
|
deletePluginPanel,
|
|
getPluginPanelInstallPluginQuery,
|
|
getPluginPanelPlugin,
|
|
installPluginPanel,
|
|
pluginPanelPluginGetVoSchema,
|
|
updateDashboardPluginStorage,
|
|
updatePluginPanelStorage,
|
|
baseQuerySchemaVo,
|
|
urlBuilder,
|
|
GET_PLUGIN_PANEL_INSTALL_PLUGIN_QUERY,
|
|
deleteDashboard,
|
|
installPlugin,
|
|
getDashboardInstallPlugin,
|
|
getDashboardInstallPluginQuery,
|
|
GET_DASHBOARD_INSTALL_PLUGIN_QUERY,
|
|
getDashboardInstallPluginVoSchema,
|
|
} from '@teable/openapi';
|
|
import { createAnonymousUserAxios } from './utils/axios-instance/anonymous-user';
|
|
import { createTable, initApp, permanentDeleteTable } from './utils/init-app';
|
|
|
|
describe('PluginController', () => {
|
|
let app: INestApplication;
|
|
let anonymousUser: ReturnType<typeof createAnonymousUserAxios>;
|
|
beforeAll(async () => {
|
|
const appCtx = await initApp();
|
|
app = appCtx.app;
|
|
anonymousUser = createAnonymousUserAxios(appCtx.appUrl);
|
|
});
|
|
|
|
afterAll(async () => {
|
|
await app.close();
|
|
});
|
|
|
|
describe('Plugin Chart', () => {
|
|
let pluginPanelId: string;
|
|
let table: ITableFullVo;
|
|
const baseId = globalThis.testConfig.baseId;
|
|
|
|
beforeEach(async () => {
|
|
table = await createTable(baseId, {
|
|
fields: [
|
|
{
|
|
name: 'name',
|
|
type: FieldType.SingleLineText,
|
|
},
|
|
{
|
|
name: 'age',
|
|
type: FieldType.Number,
|
|
},
|
|
],
|
|
records: [
|
|
{
|
|
fields: {
|
|
name: 'Alice',
|
|
age: 20,
|
|
},
|
|
},
|
|
{
|
|
fields: {
|
|
name: 'Bob',
|
|
age: 30,
|
|
},
|
|
},
|
|
{
|
|
fields: {
|
|
name: 'Charlie',
|
|
age: 40,
|
|
},
|
|
},
|
|
],
|
|
});
|
|
});
|
|
|
|
afterEach(async () => {
|
|
await deletePluginPanel(table.id, pluginPanelId);
|
|
await permanentDeleteTable(baseId, table.id);
|
|
});
|
|
|
|
async function preparePluginPanel(table: ITableFullVo) {
|
|
const pluginPanelRes = await createPluginPanel(table.id, {
|
|
name: 'plugin panel',
|
|
});
|
|
pluginPanelId = pluginPanelRes.data.id;
|
|
|
|
const pluginId = 'plgchart';
|
|
|
|
const installRes = await installPluginPanel(table.id, pluginPanelId, {
|
|
name: 'plugin',
|
|
pluginId,
|
|
});
|
|
const pluginInstallId = installRes.data.pluginInstallId;
|
|
const textField = table.fields.find((field) => field.type === FieldType.SingleLineText)!;
|
|
const numberField = table.fields.find((field) => field.type === FieldType.Number)!;
|
|
const res = await getPluginPanelPlugin(table.id, pluginPanelId, pluginInstallId);
|
|
expect(res.status).toBe(200);
|
|
expect(pluginPanelPluginGetVoSchema.strict().safeParse(res.data).success).toBe(true);
|
|
expect(res.data.pluginId).toBe(pluginId);
|
|
|
|
await updatePluginPanelStorage(table.id, pluginPanelId, pluginInstallId, {
|
|
storage: {
|
|
config: {
|
|
type: 'bar',
|
|
xAxis: [{ column: textField.name, display: { type: 'bar', position: 'auto' } }],
|
|
yAxis: [{ column: numberField.name, display: { type: 'bar', position: 'auto' } }],
|
|
},
|
|
query: {
|
|
from: table.id,
|
|
select: [
|
|
{ column: textField.id, alias: textField.name, type: 'field' },
|
|
{ column: numberField.id, alias: numberField.name, type: 'field' },
|
|
],
|
|
},
|
|
},
|
|
});
|
|
|
|
return { pluginPanelId, pluginId, pluginInstallId };
|
|
}
|
|
|
|
it('api/plugin/chart/:pluginInstallId/plugin-panel/:positionId/query (GET)', async () => {
|
|
const { pluginPanelId, pluginInstallId } = await preparePluginPanel(table);
|
|
|
|
const queryRes = await getPluginPanelInstallPluginQuery(pluginInstallId, pluginPanelId, {
|
|
tableId: table.id,
|
|
});
|
|
expect(queryRes.status).toBe(200);
|
|
expect(baseQuerySchemaVo.strict().safeParse(queryRes.data).success).toBe(true);
|
|
|
|
await expect(
|
|
anonymousUser.get<IBaseQueryVo>(
|
|
urlBuilder(GET_PLUGIN_PANEL_INSTALL_PLUGIN_QUERY, {
|
|
pluginInstallId: pluginInstallId,
|
|
positionId: pluginPanelId,
|
|
}),
|
|
{
|
|
params: { tableId: table.id },
|
|
}
|
|
)
|
|
).rejects.toThrow();
|
|
});
|
|
});
|
|
|
|
describe('Dashboard Chart', () => {
|
|
let dashboardId: string;
|
|
let table: ITableFullVo;
|
|
const baseId = globalThis.testConfig.baseId;
|
|
|
|
beforeEach(async () => {
|
|
table = await createTable(baseId, {
|
|
fields: [
|
|
{
|
|
name: 'name',
|
|
type: FieldType.SingleLineText,
|
|
},
|
|
{
|
|
name: 'age',
|
|
type: FieldType.Number,
|
|
},
|
|
],
|
|
records: [
|
|
{
|
|
fields: {
|
|
name: 'Alice',
|
|
age: 20,
|
|
},
|
|
},
|
|
{
|
|
fields: {
|
|
name: 'Bob',
|
|
age: 30,
|
|
},
|
|
},
|
|
{
|
|
fields: {
|
|
name: 'Charlie',
|
|
age: 40,
|
|
},
|
|
},
|
|
],
|
|
});
|
|
});
|
|
|
|
afterEach(async () => {
|
|
await deleteDashboard(baseId, dashboardId);
|
|
await permanentDeleteTable(baseId, table.id);
|
|
});
|
|
|
|
async function prepareDashboard(table: ITableFullVo) {
|
|
const dashboardRes = await createDashboard(baseId, {
|
|
name: 'dashboard',
|
|
});
|
|
dashboardId = dashboardRes.data.id;
|
|
|
|
const pluginId = 'plgchart';
|
|
const installRes = await installPlugin(baseId, dashboardId, {
|
|
name: 'plugin',
|
|
pluginId,
|
|
});
|
|
const pluginInstallId = installRes.data.pluginInstallId;
|
|
const textField = table.fields.find((field) => field.type === FieldType.SingleLineText)!;
|
|
const numberField = table.fields.find((field) => field.type === FieldType.Number)!;
|
|
const res = await getDashboardInstallPlugin(baseId, dashboardId, pluginInstallId);
|
|
expect(res.status).toBe(200);
|
|
expect(getDashboardInstallPluginVoSchema.strict().safeParse(res.data).success).toBe(true);
|
|
expect(res.data.pluginId).toBe(pluginId);
|
|
|
|
await updateDashboardPluginStorage(baseId, dashboardId, pluginInstallId, {
|
|
config: {
|
|
type: 'bar',
|
|
xAxis: [{ column: textField.name, display: { type: 'bar', position: 'auto' } }],
|
|
yAxis: [{ column: numberField.name, display: { type: 'bar', position: 'auto' } }],
|
|
},
|
|
query: {
|
|
from: table.id,
|
|
select: [
|
|
{ column: textField.id, alias: textField.name, type: 'field' },
|
|
{ column: numberField.id, alias: numberField.name, type: 'field' },
|
|
],
|
|
},
|
|
});
|
|
|
|
return { dashboardId, pluginId, pluginInstallId };
|
|
}
|
|
|
|
it('api/plugin/chart/:pluginInstallId/dashboard/:positionId/query (GET)', async () => {
|
|
const { pluginInstallId, dashboardId } = await prepareDashboard(table);
|
|
const queryRes = await getDashboardInstallPluginQuery(pluginInstallId, dashboardId, {
|
|
baseId,
|
|
});
|
|
expect(queryRes.status).toBe(200);
|
|
expect(baseQuerySchemaVo.strict().safeParse(queryRes.data).success).toBe(true);
|
|
|
|
await expect(
|
|
anonymousUser.get<IBaseQueryVo>(
|
|
urlBuilder(GET_DASHBOARD_INSTALL_PLUGIN_QUERY, {
|
|
pluginInstallId,
|
|
positionId: dashboardId,
|
|
}),
|
|
{
|
|
params: { baseId },
|
|
}
|
|
)
|
|
).rejects.toThrow();
|
|
});
|
|
});
|
|
});
|