Browse Source

feat(wip): controller-service implementation

Signed-off-by: Pranav C <pranavxc@gmail.com>
pull/5239/head
Pranav C 1 year ago
parent
commit
9c9ceb7cd8
  1. 1
      packages/nc-gui/components.d.ts
  2. 410
      packages/nocodb/src/lib/controllers/tableController.ts
  3. 2
      packages/nocodb/src/lib/models/ProjectUser.ts
  4. 2
      packages/nocodb/src/lib/services/index.ts
  5. 42
      packages/nocodb/src/lib/services/projectService.ts
  6. 348
      packages/nocodb/src/lib/services/tableService.ts

1
packages/nc-gui/components.d.ts vendored

@ -89,6 +89,7 @@ declare module '@vue/runtime-core' {
IcTwotoneWidthNormal: typeof import('~icons/ic/twotone-width-normal')['default']
LogosGoogleGmail: typeof import('~icons/logos/google-gmail')['default']
LogosMysqlIcon: typeof import('~icons/logos/mysql-icon')['default']
LogosOracle: typeof import('~icons/logos/oracle')['default']
LogosPostgresql: typeof import('~icons/logos/postgresql')['default']
LogosRedditIcon: typeof import('~icons/logos/reddit-icon')['default']
LogosSnowflakeIcon: typeof import('~icons/logos/snowflake-icon')['default']

410
packages/nocodb/src/lib/controllers/tableController.ts

@ -1,404 +1,62 @@
import { Request, Response, Router } from 'express';
import Model from '../models/Model';
import { Tele } from 'nc-help';
import { PagedResponseImpl } from '../meta/helpers/PagedResponse';
import DOMPurify from 'isomorphic-dompurify';
import {
AuditOperationSubTypes,
AuditOperationTypes,
isVirtualCol,
ModelTypes,
NormalColumnRequestType,
TableListType,
TableReqType,
TableType,
UITypes,
} from 'nocodb-sdk';
import ProjectMgrv2 from '../db/sql-mgr/v2/ProjectMgrv2';
import Project from '../models/Project';
import Audit from '../models/Audit';
import ncMetaAclMw from '../meta/helpers/ncMetaAclMw';
import { TableListType, TableReqType, TableType } from 'nocodb-sdk';
import { getAjvValidatorMw } from '../meta/api/helpers';
import { xcVisibilityMetaGet } from './modelVisibilityController';
import View from '../models/View';
import getColumnPropsFromUIDT from '../meta/helpers/getColumnPropsFromUIDT';
import mapDefaultDisplayValue from '../meta/helpers/mapDefaultDisplayValue';
import { NcError } from '../meta/helpers/catchError';
import getTableNameAlias, { getColumnNameAlias } from '../meta/helpers/getTableName';
import Column from '../models/Column';
import NcConnectionMgrv2 from '../utils/common/NcConnectionMgrv2';
import getColumnUiType from '../meta/helpers/getColumnUiType';
import LinkToAnotherRecordColumn from '../models/LinkToAnotherRecordColumn';
import { tableUpdate } from '../meta/api/tableApis';
import { metaApiMetrics } from '../meta/helpers/apiMetrics';
import ncMetaAclMw from '../meta/helpers/ncMetaAclMw';
import { PagedResponseImpl } from '../meta/helpers/PagedResponse';
export async function tableGet(req: Request, res: Response<TableType>) {
const table = await Model.getWithInfo({
id: req.params.tableId,
});
// todo: optimise
const viewList = <View[]>await xcVisibilityMetaGet(table.project_id, [table]);
//await View.list(req.params.tableId)
table.views = viewList.filter((table: any) => {
return Object.keys((req as any).session?.passport?.user?.roles).some(
(role) =>
(req as any)?.session?.passport?.user?.roles[role] &&
!table.disabled[role]
);
});
res.json(table);
}
export async function tableReorder(req: Request, res: Response) {
res.json(Model.updateOrder(req.params.tableId, req.body.order));
}
import { tableService } from '../services';
export async function tableList(req: Request, res: Response<TableListType>) {
const viewList = await xcVisibilityMetaGet(req.params.projectId);
// todo: optimise
const tableViewMapping = viewList.reduce((o, view: any) => {
o[view.fk_model_id] = o[view.fk_model_id] || 0;
if (
Object.keys((req as any).session?.passport?.user?.roles).some(
(role) =>
(req as any)?.session?.passport?.user?.roles[role] &&
!view.disabled[role]
)
) {
o[view.fk_model_id]++;
}
return o;
}, {});
const tableList = (
await Model.list({
project_id: req.params.projectId,
base_id: req.params.baseId,
})
).filter((t) => tableViewMapping[t.id]);
res.json(
new PagedResponseImpl(
req.query?.includeM2M === 'true'
? tableList
: (tableList.filter((t) => !t.mm) as Model[])
await tableService.getAccessibleTables({
projectId: req.params.projectId,
baseId: req.params.baseId,
includeM2M: req.query?.includeM2M === 'true',
roles: (req as any).session?.passport?.user?.roles,
})
)
);
}
export async function tableCreate(req: Request<any, any, TableReqType>, res) {
const project = await Project.getWithInfo(req.params.projectId);
let base = project.bases[0];
if (req.params.baseId) {
base = project.bases.find((b) => b.id === req.params.baseId);
}
if (
!req.body.table_name ||
(project.prefix && project.prefix === req.body.table_name)
) {
NcError.badRequest(
'Missing table name `table_name` property in request body'
);
}
if (base.is_meta && project.prefix) {
if (!req.body.table_name.startsWith(project.prefix)) {
req.body.table_name = `${project.prefix}_${req.body.table_name}`;
}
}
req.body.table_name = DOMPurify.sanitize(req.body.table_name);
// validate table name
if (/^\s+|\s+$/.test(req.body.table_name)) {
NcError.badRequest(
'Leading or trailing whitespace not allowed in table names'
);
}
if (
!(await Model.checkTitleAvailable({
table_name: req.body.table_name,
project_id: project.id,
base_id: base.id,
}))
) {
NcError.badRequest('Duplicate table name');
}
if (!req.body.title) {
req.body.title = getTableNameAlias(
req.body.table_name,
project.prefix,
base
);
}
if (
!(await Model.checkAliasAvailable({
title: req.body.title,
project_id: project.id,
base_id: base.id,
}))
) {
NcError.badRequest('Duplicate table alias');
}
const sqlMgr = await ProjectMgrv2.getSqlMgr(project);
const sqlClient = await NcConnectionMgrv2.getSqlClient(base);
let tableNameLengthLimit = 255;
const sqlClientType = sqlClient.knex.clientType();
if (sqlClientType === 'mysql2' || sqlClientType === 'mysql') {
tableNameLengthLimit = 64;
} else if (sqlClientType === 'pg') {
tableNameLengthLimit = 63;
} else if (sqlClientType === 'mssql') {
tableNameLengthLimit = 128;
}
if (req.body.table_name.length > tableNameLengthLimit) {
NcError.badRequest(`Table name exceeds ${tableNameLengthLimit} characters`);
}
const mxColumnLength = Column.getMaxColumnNameLength(sqlClientType);
for (const column of req.body.columns) {
if (column.column_name.length > mxColumnLength) {
NcError.badRequest(
`Column name ${column.column_name} exceeds ${mxColumnLength} characters`
);
}
}
req.body.columns = req.body.columns?.map((c) => ({
...getColumnPropsFromUIDT(c as any, base),
cn: c.column_name,
}));
await sqlMgr.sqlOpPlus(base, 'tableCreate', {
...req.body,
tn: req.body.table_name,
const result = tableService.createTable({
projectId: req.params.projectId,
baseId: req.params.baseId,
table: req.body,
user: (req as any).session?.passport?.user,
});
const columns: Array<
Omit<Column, 'column_name' | 'title'> & {
cn: string;
system?: boolean;
}
> = (await sqlClient.columnList({ tn: req.body.table_name }))?.data?.list;
const tables = await Model.list({
project_id: project.id,
base_id: base.id,
});
await Audit.insert({
project_id: project.id,
base_id: base.id,
op_type: AuditOperationTypes.TABLE,
op_sub_type: AuditOperationSubTypes.CREATED,
user: (req as any)?.user?.email,
description: `created table ${req.body.table_name} with alias ${req.body.title} `,
ip: (req as any).clientIp,
}).then(() => {});
mapDefaultDisplayValue(req.body.columns);
Tele.emit('evt', { evt_type: 'table:created' });
res.json(
await Model.insert(project.id, base.id, {
...req.body,
columns: columns.map((c, i) => {
const colMetaFromReq = req.body?.columns?.find(
(c1) => c.cn === c1.column_name
) as NormalColumnRequestType;
return {
...colMetaFromReq,
uidt:
(colMetaFromReq?.uidt as string) ||
c.uidt ||
getColumnUiType(base, c),
...c,
dtxp: [UITypes.MultiSelect, UITypes.SingleSelect].includes(
colMetaFromReq.uidt as any
)
? colMetaFromReq.dtxp
: c.dtxp,
title: colMetaFromReq?.title || getColumnNameAlias(c.cn, base),
column_name: c.cn,
order: i + 1,
} as NormalColumnRequestType;
}),
order: +(tables?.pop()?.order ?? 0) + 1,
})
);
res.json(result);
}
export async function tableUpdate(req: Request<any, any>, res) {
const model = await Model.get(req.params.tableId);
const project = await Project.getWithInfo(
req.body.project_id || (req as any).ncProjectId
);
const base = project.bases.find((b) => b.id === model.base_id);
if (model.project_id !== project.id) {
NcError.badRequest('Model does not belong to project');
}
// if meta present update meta and return
// todo: allow user to update meta and other prop in single api call
if ('meta' in req.body) {
await Model.updateMeta(req.params.tableId, req.body.meta);
return res.json({ msg: 'success' });
}
if (!req.body.table_name) {
NcError.badRequest(
'Missing table name `table_name` property in request body'
);
}
if (base.is_meta && project.prefix) {
if (!req.body.table_name.startsWith(project.prefix)) {
req.body.table_name = `${project.prefix}${req.body.table_name}`;
}
}
req.body.table_name = DOMPurify.sanitize(req.body.table_name);
// validate table name
if (/^\s+|\s+$/.test(req.body.table_name)) {
NcError.badRequest(
'Leading or trailing whitespace not allowed in table names'
);
}
if (
!(await Model.checkTitleAvailable({
table_name: req.body.table_name,
project_id: project.id,
base_id: base.id,
}))
) {
NcError.badRequest('Duplicate table name');
}
if (!req.body.title) {
req.body.title = getTableNameAlias(
req.body.table_name,
project.prefix,
base
);
}
if (
!(await Model.checkAliasAvailable({
title: req.body.title,
project_id: project.id,
base_id: base.id,
}))
) {
NcError.badRequest('Duplicate table alias');
}
const sqlMgr = await ProjectMgrv2.getSqlMgr(project);
const sqlClient = await NcConnectionMgrv2.getSqlClient(base);
let tableNameLengthLimit = 255;
const sqlClientType = sqlClient.knex.clientType();
if (sqlClientType === 'mysql2' || sqlClientType === 'mysql') {
tableNameLengthLimit = 64;
} else if (sqlClientType === 'pg') {
tableNameLengthLimit = 63;
} else if (sqlClientType === 'mssql') {
tableNameLengthLimit = 128;
}
if (req.body.table_name.length > tableNameLengthLimit) {
NcError.badRequest(`Table name exceeds ${tableNameLengthLimit} characters`);
}
await Model.updateAliasAndTableName(
req.params.tableId,
req.body.title,
req.body.table_name
);
await sqlMgr.sqlOpPlus(base, 'tableRename', {
...req.body,
tn: req.body.table_name,
tn_old: model.table_name,
export async function tableGet(req: Request, res: Response<TableType>) {
const table = await tableService.getTableWithAccessibleViews({
tableId: req.params.tableId,
user: (req as any).session?.passport?.user,
});
Tele.emit('evt', { evt_type: 'table:updated' });
res.json({ msg: 'success' });
res.json(table);
}
export async function tableDelete(req: Request, res: Response) {
const table = await Model.getByIdOrName({ id: req.params.tableId });
await table.getColumns();
const relationColumns = table.columns.filter(
(c) => c.uidt === UITypes.LinkToAnotherRecord
);
if (relationColumns?.length) {
const referredTables = await Promise.all(
relationColumns.map(async (c) =>
c
.getColOptions<LinkToAnotherRecordColumn>()
.then((opt) => opt.getRelatedTable())
.then()
)
);
NcError.badRequest(
`Table can't be deleted since Table is being referred in following tables : ${referredTables.join(
', '
)}. Delete LinkToAnotherRecord columns and try again.`
);
}
const project = await Project.getWithInfo(table.project_id);
const base = project.bases.find((b) => b.id === table.base_id);
const sqlMgr = await ProjectMgrv2.getSqlMgr(project);
(table as any).tn = table.table_name;
table.columns = table.columns.filter((c) => !isVirtualCol(c));
table.columns.forEach((c) => {
(c as any).cn = c.column_name;
const result = await tableService.deleteTable({
tableId: req.params.tableId,
user: (req as any).session?.passport?.user,
});
if (table.type === ModelTypes.TABLE) {
await sqlMgr.sqlOpPlus(base, 'tableDelete', table);
} else if (table.type === ModelTypes.VIEW) {
await sqlMgr.sqlOpPlus(base, 'viewDelete', {
...table,
view_name: table.table_name,
});
}
await Audit.insert({
project_id: project.id,
base_id: base.id,
op_type: AuditOperationTypes.TABLE,
op_sub_type: AuditOperationSubTypes.DELETED,
user: (req as any)?.user?.email,
description: `Deleted ${table.type} ${table.table_name} with alias ${table.title} `,
ip: (req as any).clientIp,
}).then(() => {});
Tele.emit('evt', { evt_type: 'table:deleted' });
res.json(result);
}
res.json(await table.delete());
export async function tableReorder(req: Request, res: Response) {
res.json(
await tableService.reorderTable({
tableId: req.params.tableId,
order: req.body.order,
})
);
}
const router = Router({ mergeParams: true });

2
packages/nocodb/src/lib/models/ProjectUser.ts

@ -219,7 +219,7 @@ export default class ProjectUser {
static async getProjectsList(
userId: string,
_params: any,
_params?: any,
ncMeta = Noco.ncMeta
): Promise<ProjectType[]> {
// todo: pagination

2
packages/nocodb/src/lib/services/index.ts

@ -0,0 +1,2 @@
// export * as projectService from './projectService';
export * as tableService from './tableService';

42
packages/nocodb/src/lib/services/projectService.ts

@ -0,0 +1,42 @@
// // services/project.service.ts
// import { OrgUserRoles, ProjectType } from 'nocodb-sdk'
// import Project from '../models/Project'
// import ProjectUser from '../models/ProjectUser'
// import { customAlphabet } from 'nanoid'
// import { NcError } from './helpers/catchError'
//
// const nanoid = customAlphabet('1234567890abcdefghijklmnopqrstuvwxyz_', 4)
//
// export async function getProjectWithInfo(projectId: string) {
// const project = await Project.getWithInfo(projectId)
// return project
// }
//
// export function sanitizeProject(project: any) {
// const sanitizedProject = { ...project }
// sanitizedProject.bases?.forEach((b: any) => {
// ['config'].forEach((k) => delete b[k])
// })
// return sanitizedProject
// }
//
// export async function updateProject(projectId: string, data: Partial<ProjectType>) {
// const project = await Project.getWithInfo(projectId)
// if (data?.title && project.title !== data.title && (await Project.getByTitle(data.title))) {
// NcError.badRequest('Project title already in use')
// }
// const result = await Project.update(projectId, data)
// return result
// }
//
// export async function listProjects(user: any) {
// const projects = user?.roles?.includes(OrgUserRoles.SUPER_ADMIN)
// ? await Project.list()
// : await ProjectUser.getProjectsList(user.id)
// return projects as ProjectType[]
// }
//
// export async function softDeleteProject(projectId: string) {
// const result = await Project.softDelete(projectId)
// return result
// }

348
packages/nocodb/src/lib/services/tableService.ts

@ -0,0 +1,348 @@
// @ts-ignore
import DOMPurify from 'isomorphic-dompurify';
import {
AuditOperationSubTypes,
AuditOperationTypes,
isVirtualCol,
ModelTypes,
NormalColumnRequestType,
TableReqType,
UITypes,
} from 'nocodb-sdk';
import ProjectMgrv2 from '../db/sql-mgr/v2/ProjectMgrv2';
import { NcError } from '../meta/helpers/catchError';
import getColumnPropsFromUIDT from '../meta/helpers/getColumnPropsFromUIDT';
import getColumnUiType from '../meta/helpers/getColumnUiType';
import getTableNameAlias, {
getColumnNameAlias,
} from '../meta/helpers/getTableName';
import mapDefaultDisplayValue from '../meta/helpers/mapDefaultDisplayValue';
import Audit from '../models/Audit';
import Column from '../models/Column';
import LinkToAnotherRecordColumn from '../models/LinkToAnotherRecordColumn';
import Model from '../models/Model';
import ModelRoleVisibility from '../models/ModelRoleVisibility';
import Project from '../models/Project';
import User from '../models/User';
import View from '../models/View';
import NcConnectionMgrv2 from '../utils/common/NcConnectionMgrv2';
import { Tele } from 'nc-help';
export function reorderTable(param: { tableId: string; order: any }) {
return Model.updateOrder(param.tableId, param.order);
}
export async function deleteTable(param: { tableId: string; user: User }) {
const table = await Model.getByIdOrName({ id: param.tableId });
await table.getColumns();
const relationColumns = table.columns.filter(
(c) => c.uidt === UITypes.LinkToAnotherRecord
);
if (relationColumns?.length) {
const referredTables = await Promise.all(
relationColumns.map(async (c) =>
c
.getColOptions<LinkToAnotherRecordColumn>()
.then((opt) => opt.getRelatedTable())
.then()
)
);
NcError.badRequest(
`Table can't be deleted since Table is being referred in following tables : ${referredTables.join(
', '
)}. Delete LinkToAnotherRecord columns and try again.`
);
}
const project = await Project.getWithInfo(table.project_id);
const base = project.bases.find((b) => b.id === table.base_id);
const sqlMgr = await ProjectMgrv2.getSqlMgr(project);
(table as any).tn = table.table_name;
table.columns = table.columns.filter((c) => !isVirtualCol(c));
table.columns.forEach((c) => {
(c as any).cn = c.column_name;
});
if (table.type === ModelTypes.TABLE) {
await sqlMgr.sqlOpPlus(base, 'tableDelete', table);
} else if (table.type === ModelTypes.VIEW) {
await sqlMgr.sqlOpPlus(base, 'viewDelete', {
...table,
view_name: table.table_name,
});
}
await Audit.insert({
project_id: project.id,
base_id: base.id,
op_type: AuditOperationTypes.TABLE,
op_sub_type: AuditOperationSubTypes.DELETED,
user: param.user?.email,
description: `Deleted ${table.type} ${table.table_name} with alias ${table.title} `,
// ip: (req as any).clientIp,
}).then(() => {});
Tele.emit('evt', { evt_type: 'table:deleted' });
return table.delete();
}
export async function getTableWithAccessibleViews(param: {
tableId: string;
user: User;
}) {
const table = await Model.getWithInfo({
id: param.tableId,
});
// todo: optimise
const viewList = <View[]>await xcVisibilityMetaGet(table.project_id, [table]);
//await View.list(req.params.tableId)
table.views = viewList.filter((table: any) => {
return Object.keys(param.user?.roles).some(
(role) => param.user?.roles[role] && !table.disabled[role]
);
});
return table;
}
export async function xcVisibilityMetaGet(
projectId,
_models: Model[] = null,
includeM2M = true
// type: 'table' | 'tableAndViews' | 'views' = 'table'
) {
// todo: move to
const roles = ['owner', 'creator', 'viewer', 'editor', 'commenter', 'guest'];
const defaultDisabled = roles.reduce((o, r) => ({ ...o, [r]: false }), {});
let models =
_models ||
(await Model.list({
project_id: projectId,
base_id: undefined,
}));
models = includeM2M ? models : (models.filter((t) => !t.mm) as Model[]);
const result = await models.reduce(async (_obj, model) => {
const obj = await _obj;
const views = await model.getViews();
for (const view of views) {
obj[view.id] = {
ptn: model.table_name,
_ptn: model.title,
ptype: model.type,
tn: view.title,
_tn: view.title,
table_meta: model.meta,
...view,
disabled: { ...defaultDisabled },
};
}
return obj;
}, Promise.resolve({}));
const disabledList = await ModelRoleVisibility.list(projectId);
for (const d of disabledList) {
if (result[d.fk_view_id])
result[d.fk_view_id].disabled[d.role] = !!d.disabled;
}
return Object.values(result);
}
export async function getAccessibleTables(param: {
projectId: string;
baseId: string;
includeM2M?: boolean;
roles: Record<string, boolean>;
}) {
const viewList = await xcVisibilityMetaGet(param.projectId);
// todo: optimise
const tableViewMapping = viewList.reduce((o, view: any) => {
o[view.fk_model_id] = o[view.fk_model_id] || 0;
if (
Object.keys(param.roles).some(
(role) => param.roles[role] && !view.disabled[role]
)
) {
o[view.fk_model_id]++;
}
return o;
}, {});
const tableList = (
await Model.list({
project_id: param.projectId,
base_id: param.baseId,
})
).filter((t) => tableViewMapping[t.id]);
return param.includeM2M
? tableList
: (tableList.filter((t) => !t.mm) as Model[]);
}
export async function createTable(args: {
projectId: string;
baseId?: string;
table: TableReqType;
user: User;
}) {
const project = await Project.getWithInfo(args.projectId);
let base = project.bases[0];
if (args.baseId) {
base = project.bases.find((b) => b.id === args.baseId);
}
if (
!args.table.table_name ||
(project.prefix && project.prefix === args.table.table_name)
) {
NcError.badRequest(
'Missing table name `table_name` property in request body'
);
}
if (base.is_meta && project.prefix) {
if (!args.table.table_name.startsWith(project.prefix)) {
args.table.table_name = `${project.prefix}_${args.table.table_name}`;
}
}
args.table.table_name = DOMPurify.sanitize(args.table.table_name);
// validate table name
if (/^\s+|\s+$/.test(args.table.table_name)) {
NcError.badRequest(
'Leading or trailing whitespace not allowed in table names'
);
}
if (
!(await Model.checkTitleAvailable({
table_name: args.table.table_name,
project_id: project.id,
base_id: base.id,
}))
) {
NcError.badRequest('Duplicate table name');
}
if (!args.table.title) {
args.table.title = getTableNameAlias(
args.table.table_name,
project.prefix,
base
);
}
if (
!(await Model.checkAliasAvailable({
title: args.table.title,
project_id: project.id,
base_id: base.id,
}))
) {
NcError.badRequest('Duplicate table alias');
}
const sqlMgr = await ProjectMgrv2.getSqlMgr(project);
const sqlClient = await NcConnectionMgrv2.getSqlClient(base);
let tableNameLengthLimit = 255;
const sqlClientType = sqlClient.knex.clientType();
if (sqlClientType === 'mysql2' || sqlClientType === 'mysql') {
tableNameLengthLimit = 64;
} else if (sqlClientType === 'pg') {
tableNameLengthLimit = 63;
} else if (sqlClientType === 'mssql') {
tableNameLengthLimit = 128;
}
if (args.table.table_name.length > tableNameLengthLimit) {
NcError.badRequest(`Table name exceeds ${tableNameLengthLimit} characters`);
}
const mxColumnLength = Column.getMaxColumnNameLength(sqlClientType);
for (const column of args.table.columns) {
if (column.column_name.length > mxColumnLength) {
NcError.badRequest(
`Column name ${column.column_name} exceeds ${mxColumnLength} characters`
);
}
}
args.table.columns = args.table.columns?.map((c) => ({
...getColumnPropsFromUIDT(c as any, base),
cn: c.column_name,
}));
await sqlMgr.sqlOpPlus(base, 'tableCreate', {
...args.table,
tn: args.table.table_name,
});
const columns: Array<
Omit<Column, 'column_name' | 'title'> & {
cn: string;
system?: boolean;
}
> = (await sqlClient.columnList({ tn: args.table.table_name }))?.data?.list;
const tables = await Model.list({
project_id: project.id,
base_id: base.id,
});
await Audit.insert({
project_id: project.id,
base_id: base.id,
op_type: AuditOperationTypes.TABLE,
op_sub_type: AuditOperationSubTypes.CREATED,
user: args.user?.email,
description: `created table ${args.table.table_name} with alias ${args.table.title} `,
// ip: (req as any).clientIp,
}).then(() => {});
mapDefaultDisplayValue(args.table.columns);
Tele.emit('evt', { evt_type: 'table:created' });
const result = await Model.insert(project.id, base.id, {
...args.table,
columns: columns.map((c, i) => {
const colMetaFromReq = args.table?.columns?.find(
(c1) => c.cn === c1.column_name
);
return {
...colMetaFromReq,
uidt: colMetaFromReq?.uidt || c.uidt || getColumnUiType(base, c),
...c,
dtxp: [UITypes.MultiSelect, UITypes.SingleSelect].includes(
colMetaFromReq.uidt as any
)
? colMetaFromReq.dtxp
: c.dtxp,
title: colMetaFromReq?.title || getColumnNameAlias(c.cn, base),
column_name: c.cn,
order: i + 1,
} as NormalColumnRequestType;
}),
order: +(tables?.pop()?.order ?? 0) + 1,
});
return result;
}
Loading…
Cancel
Save