Browse Source

Merge pull request #3414 from nocodb/fix/3412-hm-mm-in-shared-view

fix: expand option of hm and mm in shared view
pull/3421/head
Raju Udava 2 years ago committed by GitHub
parent
commit
2da8b6cef7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 4
      packages/nc-gui-v2/components/smartsheet/Gallery.vue
  2. 4
      packages/nc-gui-v2/components/virtual-cell/ManyToMany.vue
  3. 1
      packages/nc-gui-v2/components/virtual-cell/components/ListChildItems.vue
  4. 42
      packages/nc-gui-v2/composables/useLTARStore.ts
  5. 15
      packages/nocodb/src/lib/meta/api/dataApis/dataAliasNestedApis.ts
  6. 15
      packages/nocodb/src/lib/meta/api/dataApis/helpers.ts
  7. 17
      packages/nocodb/src/lib/meta/api/publicApis/publicDataApis.ts
  8. 22
      packages/nocodb/src/lib/meta/helpers/PagedResponse.ts
  9. 58
      packages/nocodb/src/lib/models/Column.ts

4
packages/nc-gui-v2/components/smartsheet/Gallery.vue

@ -203,10 +203,10 @@ openNewRecordFormHook?.on(async () => {
display: block; display: block;
font-size: 0; font-size: 0;
height: 3px; height: 3px;
opacity: .3; opacity: 0.3;
outline: none; outline: none;
padding: 0; padding: 0;
transition: all .5s; transition: all 0.5s;
width: 100%; width: 100%;
} }
.ant-carousel.gallery-carousel :deep(.slick-dots li.slick-active div > div) { .ant-carousel.gallery-carousel :deep(.slick-dots li.slick-active div > div) {

4
packages/nc-gui-v2/components/virtual-cell/ManyToMany.vue

@ -94,14 +94,14 @@ const unlinkRef = async (rec: Record<string, any>) => {
</template> </template>
</div> </div>
<div v-if="!isLocked && isUIAllowed('xcDatatableEditable')" class="flex justify-end gap-1 min-h-[30px] items-center"> <div v-if="!isLocked" class="flex justify-end gap-1 min-h-[30px] items-center">
<MdiArrowExpand <MdiArrowExpand
class="text-sm nc-action-icon text-gray-500/50 hover:text-gray-500 nc-arrow-expand" class="text-sm nc-action-icon text-gray-500/50 hover:text-gray-500 nc-arrow-expand"
@click="childListDlg = true" @click="childListDlg = true"
/> />
<MdiPlus <MdiPlus
v-if="!readOnly" v-if="!readOnly && isUIAllowed('xcDatatableEditable')"
class="text-sm nc-action-icon text-gray-500/50 hover:text-gray-500 nc-plus" class="text-sm nc-action-icon text-gray-500/50 hover:text-gray-500 nc-plus"
@click="listItemsDlg = true" @click="listItemsDlg = true"
/> />

1
packages/nc-gui-v2/components/virtual-cell/components/ListChildItems.vue

@ -101,6 +101,7 @@ const expandedFormRow = ref()
class="!my-4 hover:(!bg-gray-200/50 shadow-md)" class="!my-4 hover:(!bg-gray-200/50 shadow-md)"
@click=" @click="
() => { () => {
if (readonly) return
expandedFormRow = row expandedFormRow = row
expandedFormDlg = true expandedFormDlg = true
} }

42
packages/nc-gui-v2/composables/useLTARStore.ts

@ -150,19 +150,35 @@ const [useProvideLTARStore, useLTARStore] = useInjectionState(
try { try {
if (colOptions.type === 'bt') return if (colOptions.type === 'bt') return
childrenList.value = await $api.dbTableRow.nestedList( if (isPublic) {
NOCO, childrenList.value = await $api.public.dataNestedList(
(project?.value?.id || sharedView?.value?.view?.project_id) as string, sharedView.value?.uuid as string,
meta.value.id, rowId.value,
rowId.value, colOptions.type as 'mm' | 'hm',
colOptions.type as 'mm' | 'hm', encodeURIComponent(column?.value?.id),
encodeURIComponent(column?.value?.title), {
{ limit: String(childrenListPagination.size),
limit: String(childrenListPagination.size), offset: String(childrenListPagination.size * (childrenListPagination.page - 1)),
offset: String(childrenListPagination.size * (childrenListPagination.page - 1)), where:
where: childrenListPagination.query && `(${relatedTablePrimaryValueProp.value},like,${childrenListPagination.query})`, childrenListPagination.query && `(${relatedTablePrimaryValueProp.value},like,${childrenListPagination.query})`,
} as any, } as any,
) )
} else {
childrenList.value = await $api.dbTableRow.nestedList(
NOCO,
(project?.value?.id || sharedView?.value?.view?.project_id) as string,
meta.value.id,
rowId.value,
colOptions.type as 'mm' | 'hm',
encodeURIComponent(column?.value?.title),
{
limit: String(childrenListPagination.size),
offset: String(childrenListPagination.size * (childrenListPagination.page - 1)),
where:
childrenListPagination.query && `(${relatedTablePrimaryValueProp.value},like,${childrenListPagination.query})`,
} as any,
)
}
} catch (e: any) { } catch (e: any) {
message.error(`Failed to load children list: ${await extractSdkResponseErrorMsg(e)}`) message.error(`Failed to load children list: ${await extractSdkResponseErrorMsg(e)}`)
} }

15
packages/nocodb/src/lib/meta/api/dataApis/dataAliasNestedApis.ts

@ -4,7 +4,7 @@ import Base from '../../../models/Base';
import NcConnectionMgrv2 from '../../../utils/common/NcConnectionMgrv2'; import NcConnectionMgrv2 from '../../../utils/common/NcConnectionMgrv2';
import { PagedResponseImpl } from '../../helpers/PagedResponse'; import { PagedResponseImpl } from '../../helpers/PagedResponse';
import ncMetaAclMw from '../../helpers/ncMetaAclMw'; import ncMetaAclMw from '../../helpers/ncMetaAclMw';
import { getViewAndModelFromRequestByAliasOrId } from './helpers'; import { getColumnByIdOrName, getViewAndModelFromRequestByAliasOrId } from './helpers'
import { NcError } from '../../helpers/catchError'; import { NcError } from '../../helpers/catchError';
import apiMetrics from '../../helpers/apiMetrics'; import apiMetrics from '../../helpers/apiMetrics';
@ -240,19 +240,6 @@ async function relationDataAdd(req, res) {
res.json({ msg: 'success' }); res.json({ msg: 'success' });
} }
async function getColumnByIdOrName(columnNameOrId: string, model: Model) {
const column = (await model.getColumns()).find(
(c) =>
c.title === columnNameOrId ||
c.id === columnNameOrId ||
c.column_name === columnNameOrId
);
if (!column)
NcError.notFound(`Column with id/name '${columnNameOrId}' is not found`);
return column;
}
const router = Router({ mergeParams: true }); const router = Router({ mergeParams: true });

15
packages/nocodb/src/lib/meta/api/dataApis/helpers.ts

@ -229,3 +229,18 @@ export async function serializeCellValue({
return value; return value;
} }
} }
export async function getColumnByIdOrName(columnNameOrId: string, model: Model) {
const column = (await model.getColumns()).find(
(c) =>
c.title === columnNameOrId ||
c.id === columnNameOrId ||
c.column_name === columnNameOrId
);
if (!column)
NcError.notFound(`Column with id/name '${columnNameOrId}' is not found`);
return column;
}

17
packages/nocodb/src/lib/meta/api/publicApis/publicDataApis.ts

@ -17,6 +17,7 @@ import { mimeIcons } from '../../../utils/mimeTypes';
import slash from 'slash'; import slash from 'slash';
import { sanitizeUrlPath } from '../attachmentApis'; import { sanitizeUrlPath } from '../attachmentApis';
import getAst from '../../../db/sql-data-mapper/lib/sql/helpers/getAst'; import getAst from '../../../db/sql-data-mapper/lib/sql/helpers/getAst';
import { getColumnByIdOrName } from '../dataApis/helpers';
export async function dataList(req: Request, res: Response) { export async function dataList(req: Request, res: Response) {
try { try {
@ -219,7 +220,10 @@ export async function publicMmList(req: Request, res: Response) {
NcError.forbidden(ErrorMessages.INVALID_SHARED_VIEW_PASSWORD); NcError.forbidden(ErrorMessages.INVALID_SHARED_VIEW_PASSWORD);
} }
const column = await Column.get({ colId: req.params.colId }); const column = await getColumnByIdOrName(
req.params.colId,
await view.getModel()
);
if (column.fk_model_id !== view.fk_model_id) if (column.fk_model_id !== view.fk_model_id)
NcError.badRequest("Column doesn't belongs to the model"); NcError.badRequest("Column doesn't belongs to the model");
@ -275,7 +279,10 @@ export async function publicHmList(req: Request, res: Response) {
NcError.forbidden(ErrorMessages.INVALID_SHARED_VIEW_PASSWORD); NcError.forbidden(ErrorMessages.INVALID_SHARED_VIEW_PASSWORD);
} }
const column = await Column.get({ colId: req.params.colId }); const column = await getColumnByIdOrName(
req.params.colId,
await view.getModel()
);
if (column.fk_model_id !== view.fk_model_id) if (column.fk_model_id !== view.fk_model_id)
NcError.badRequest("Column doesn't belongs to the model"); NcError.badRequest("Column doesn't belongs to the model");
@ -317,11 +324,7 @@ export async function publicHmList(req: Request, res: Response) {
id: req.params.rowId, id: req.params.rowId,
}); });
res.json( res.json(new PagedResponseImpl(data, { ...req.query, count }));
new PagedResponseImpl(data, {
totalRows: count,
} as any)
);
} }
const router = Router({ mergeParams: true }); const router = Router({ mergeParams: true });

22
packages/nocodb/src/lib/meta/helpers/PagedResponse.ts

@ -5,21 +5,31 @@ const config: any = {
limitMin: Math.max(+process.env.DB_QUERY_LIMIT_MIN || 1, 1), limitMin: Math.max(+process.env.DB_QUERY_LIMIT_MIN || 1, 1),
limitMax: Math.max(+process.env.DB_QUERY_LIMIT_MAX || 1000, 1), limitMax: Math.max(+process.env.DB_QUERY_LIMIT_MAX || 1000, 1),
}; };
export class PagedResponseImpl<T> { export class PagedResponseImpl<T> {
constructor( constructor(
list: T[], list: T[],
args: { limit?: number; offset?: number; count?: number, l?: number, o?: number } = {} args: {
limit?: number;
offset?: number;
count?: number | string;
l?: number;
o?: number;
} = {}
) { ) {
const limit = Math.max( const limit = Math.max(
Math.min( Math.min(args.limit || args.l || config.limitDefault, config.limitMax),
args.limit || args.l || config.limitDefault,
config.limitMax
),
config.limitMin config.limitMin
); );
const offset = Math.max(+(args.offset || args.o) || 0, 0); const offset = Math.max(+(args.offset || args.o) || 0, 0);
const count = args.count ?? null;
let count = args.count ?? null;
if (count !== null) count = +count;
this.list = list; this.list = list;
if (count !== null) { if (count !== null) {
this.pageInfo = { totalRows: +count }; this.pageInfo = { totalRows: +count };
this.pageInfo.page = offset ? offset / limit + 1 : 1; this.pageInfo.page = offset ? offset / limit + 1 : 1;

58
packages/nocodb/src/lib/models/Column.ts

@ -232,20 +232,33 @@ export default class Column<T = any> implements ColumnType {
} }
case UITypes.MultiSelect: { case UITypes.MultiSelect: {
if (!column.colOptions?.options) { if (!column.colOptions?.options) {
const selectColors = [ '#cfdffe', '#d0f1fd', '#c2f5e8', '#ffdaf6', '#ffdce5', '#fee2d5', '#ffeab6', '#d1f7c4', '#ede2fe', '#eeeeee', ]; const selectColors = [
for (const [i, option] of column.dtxp?.split(',').entries() || [].entries()) { '#cfdffe',
'#d0f1fd',
'#c2f5e8',
'#ffdaf6',
'#ffdce5',
'#fee2d5',
'#ffeab6',
'#d1f7c4',
'#ede2fe',
'#eeeeee',
];
for (const [i, option] of column.dtxp?.split(',').entries() ||
[].entries()) {
await SelectOption.insert( await SelectOption.insert(
{ {
fk_column_id: colId, fk_column_id: colId,
title: option.replace(/^'/, '').replace(/'$/, ''), title: option.replace(/^'/, '').replace(/'$/, ''),
order: i + 1, order: i + 1,
color: selectColors[i % selectColors.length] color: selectColors[i % selectColors.length],
}, },
ncMeta ncMeta
); );
} }
} else { } else {
for (const [i, option] of column.colOptions.options.entries() || [].entries()) { for (const [i, option] of column.colOptions.options.entries() ||
[].entries()) {
// Trim end of enum/set // Trim end of enum/set
if (column.dt === 'enum' || column.dt === 'set') { if (column.dt === 'enum' || column.dt === 'set') {
option.title = option.title.trimEnd(); option.title = option.title.trimEnd();
@ -254,7 +267,7 @@ export default class Column<T = any> implements ColumnType {
{ {
...option, ...option,
fk_column_id: colId, fk_column_id: colId,
order: i + 1 order: i + 1,
}, },
ncMeta ncMeta
); );
@ -264,20 +277,33 @@ export default class Column<T = any> implements ColumnType {
} }
case UITypes.SingleSelect: { case UITypes.SingleSelect: {
if (!column.colOptions?.options) { if (!column.colOptions?.options) {
const selectColors = [ '#cfdffe', '#d0f1fd', '#c2f5e8', '#ffdaf6', '#ffdce5', '#fee2d5', '#ffeab6', '#d1f7c4', '#ede2fe', '#eeeeee', ]; const selectColors = [
for (const [i, option] of column.dtxp?.split(',').entries() || [].entries()) { '#cfdffe',
'#d0f1fd',
'#c2f5e8',
'#ffdaf6',
'#ffdce5',
'#fee2d5',
'#ffeab6',
'#d1f7c4',
'#ede2fe',
'#eeeeee',
];
for (const [i, option] of column.dtxp?.split(',').entries() ||
[].entries()) {
await SelectOption.insert( await SelectOption.insert(
{ {
fk_column_id: colId, fk_column_id: colId,
title: option.replace(/^'/, '').replace(/'$/, ''), title: option.replace(/^'/, '').replace(/'$/, ''),
order: i + 1, order: i + 1,
color: selectColors[i % selectColors.length] color: selectColors[i % selectColors.length],
}, },
ncMeta ncMeta
); );
} }
} else { } else {
for (const [i, option] of column.colOptions.options.entries() || [].entries()) { for (const [i, option] of column.colOptions.options.entries() ||
[].entries()) {
// Trim end of enum/set // Trim end of enum/set
if (column.dt === 'enum' || column.dt === 'set') { if (column.dt === 'enum' || column.dt === 'set') {
option.title = option.title.trimEnd(); option.title = option.title.trimEnd();
@ -286,7 +312,7 @@ export default class Column<T = any> implements ColumnType {
{ {
...option, ...option,
fk_column_id: colId, fk_column_id: colId,
order: i + 1 order: i + 1,
}, },
ncMeta ncMeta
); );
@ -507,12 +533,14 @@ export default class Column<T = any> implements ColumnType {
MetaTable.COLUMNS, MetaTable.COLUMNS,
colId colId
); );
try { if (colData) {
colData.meta = JSON.parse(colData.meta); try {
} catch { colData.meta = JSON.parse(colData.meta);
colData.meta = {}; } catch {
colData.meta = {};
}
await NocoCache.set(`${CacheScope.COLUMN}:${colId}`, colData);
} }
await NocoCache.set(`${CacheScope.COLUMN}:${colId}`, colData);
} }
if (colData) { if (colData) {
const column = new Column(colData); const column = new Column(colData);

Loading…
Cancel
Save