Browse Source

feat: allow editing rollup and lookup column

Signed-off-by: Pranav C <pranavxc@gmail.com>
pull/5091/head
Pranav C 2 years ago
parent
commit
db760af901
  1. 4
      packages/nc-gui/components/smartsheet/column/EditOrAdd.vue
  2. 16
      packages/nc-gui/components/smartsheet/column/LookupOptions.vue
  3. 13
      packages/nc-gui/components/smartsheet/column/RollupOptions.vue
  4. 197
      packages/nocodb/src/lib/meta/api/columnApis.ts

4
packages/nc-gui/components/smartsheet/column/EditOrAdd.vue

@ -181,10 +181,10 @@ useEventListener('keydown', (e: KeyboardEvent) => {
<LazySmartsheetColumnDurationOptions v-if="formState.uidt === UITypes.Duration" v-model:value="formState" /> <LazySmartsheetColumnDurationOptions v-if="formState.uidt === UITypes.Duration" v-model:value="formState" />
<LazySmartsheetColumnRatingOptions v-if="formState.uidt === UITypes.Rating" v-model:value="formState" /> <LazySmartsheetColumnRatingOptions v-if="formState.uidt === UITypes.Rating" v-model:value="formState" />
<LazySmartsheetColumnCheckboxOptions v-if="formState.uidt === UITypes.Checkbox" v-model:value="formState" /> <LazySmartsheetColumnCheckboxOptions v-if="formState.uidt === UITypes.Checkbox" v-model:value="formState" />
<LazySmartsheetColumnLookupOptions v-if="!isEdit && formState.uidt === UITypes.Lookup" v-model:value="formState" /> <LazySmartsheetColumnLookupOptions v-if="formState.uidt === UITypes.Lookup" v-model:value="formState" />
<LazySmartsheetColumnDateOptions v-if="formState.uidt === UITypes.Date" v-model:value="formState" /> <LazySmartsheetColumnDateOptions v-if="formState.uidt === UITypes.Date" v-model:value="formState" />
<LazySmartsheetColumnDateTimeOptions v-if="formState.uidt === UITypes.DateTime" v-model:value="formState" /> <LazySmartsheetColumnDateTimeOptions v-if="formState.uidt === UITypes.DateTime" v-model:value="formState" />
<LazySmartsheetColumnRollupOptions v-if="!isEdit && formState.uidt === UITypes.Rollup" v-model:value="formState" /> <LazySmartsheetColumnRollupOptions v-if="formState.uidt === UITypes.Rollup" v-model:value="formState" />
<LazySmartsheetColumnLinkedToAnotherRecordOptions <LazySmartsheetColumnLinkedToAnotherRecordOptions
v-if="!isEdit && formState.uidt === UITypes.LinkToAnotherRecord" v-if="!isEdit && formState.uidt === UITypes.LinkToAnotherRecord"
v-model:value="formState" v-model:value="formState"

16
packages/nc-gui/components/smartsheet/column/LookupOptions.vue

@ -1,4 +1,5 @@
<script setup lang="ts"> <script setup lang="ts">
import { onMounted } from '@vue/runtime-core'
import type { ColumnType, LinkToAnotherRecordType, TableType } from 'nocodb-sdk' import type { ColumnType, LinkToAnotherRecordType, TableType } from 'nocodb-sdk'
import { UITypes, isSystemColumn } from 'nocodb-sdk' import { UITypes, isSystemColumn } from 'nocodb-sdk'
import { getRelationName } from './utils' import { getRelationName } from './utils'
@ -14,7 +15,7 @@ const vModel = useVModel(props, 'value', emit)
const meta = $(inject(MetaInj, ref())) const meta = $(inject(MetaInj, ref()))
const { setAdditionalValidations, validateInfos, onDataTypeChange } = useColumnCreateStoreOrThrow() const { setAdditionalValidations, validateInfos, onDataTypeChange, isEdit } = useColumnCreateStoreOrThrow()
const { tables } = $(useProject()) const { tables } = $(useProject())
@ -51,12 +52,23 @@ const columns = $computed<ColumnType[]>(() => {
} }
return metas[selectedTable.id].columns.filter((c: ColumnType) => !isSystemColumn(c)) return metas[selectedTable.id].columns.filter((c: ColumnType) => !isSystemColumn(c))
}) })
onMounted(() => {
if (isEdit.value) {
vModel.value.fk_lookup_column_id = vModel.value.colOptions?.fk_lookup_column_id
vModel.value.fk_relation_column_id = vModel.value.colOptions?.fk_relation_column_id
// delete vModel.value.colOptions
}
})
</script> </script>
<template> <template>
<div class="p-6 w-full flex flex-col border-2 mb-2 mt-4"> <div class="p-6 w-full flex flex-col border-2 mb-2 mt-4">
<div class="w-full flex flex-row space-x-2"> <div class="w-full flex flex-row space-x-2">
<a-form-item class="flex w-1/2 pb-2" :label="$t('labels.linkToAnotherRecord')" v-bind="validateInfos.fk_relation_column_id"> <a-form-item class="flex w-1/2 pb-2" :label="$t('labels.linkToAnotherRecord')"
v-bind="validateInfos.fk_relation_column_id">
<a-select <a-select
v-model:value="vModel.fk_relation_column_id" v-model:value="vModel.fk_relation_column_id"
dropdown-class-name="!w-64 nc-dropdown-relation-table" dropdown-class-name="!w-64 nc-dropdown-relation-table"

13
packages/nc-gui/components/smartsheet/column/RollupOptions.vue

@ -1,4 +1,5 @@
<script setup lang="ts"> <script setup lang="ts">
import { onMounted } from '@vue/runtime-core'
import type { ColumnType, LinkToAnotherRecordType, TableType } from 'nocodb-sdk' import type { ColumnType, LinkToAnotherRecordType, TableType } from 'nocodb-sdk'
import { UITypes, isSystemColumn, isVirtualCol } from 'nocodb-sdk' import { UITypes, isSystemColumn, isVirtualCol } from 'nocodb-sdk'
import { getRelationName } from './utils' import { getRelationName } from './utils'
@ -14,7 +15,7 @@ const vModel = useVModel(props, 'value', emit)
const meta = $(inject(MetaInj, ref())) const meta = $(inject(MetaInj, ref()))
const { setAdditionalValidations, validateInfos, onDataTypeChange } = useColumnCreateStoreOrThrow() const { setAdditionalValidations, validateInfos, onDataTypeChange, isEdit } = useColumnCreateStoreOrThrow()
const { tables } = $(useProject()) const { tables } = $(useProject())
@ -71,6 +72,16 @@ const columns = $computed(() => {
return metas[selectedTable.id].columns.filter((c: ColumnType) => !isVirtualCol(c.uidt as UITypes) && !isSystemColumn(c)) return metas[selectedTable.id].columns.filter((c: ColumnType) => !isVirtualCol(c.uidt as UITypes) && !isSystemColumn(c))
}) })
onMounted(() => {
if (isEdit.value) {
vModel.value.fk_relation_column_id = vModel.value.colOptions?.fk_relation_column_id
vModel.value.fk_rollup_column_id = vModel.value.colOptions?.fk_rollup_column_id
vModel.value.rollup_function = vModel.value.colOptions?.rollup_function
// delete vModel.value.colOptions
}
})
</script> </script>
<template> <template>

197
packages/nocodb/src/lib/meta/api/columnApis.ts

@ -121,6 +121,95 @@ export async function columnGet(req: Request, res: Response) {
res.json(await Column.get({ colId: req.params.columnId })); res.json(await Column.get({ colId: req.params.columnId }));
} }
async function validateRollupPayload(
payload: ColumnReqType & { uidt: UITypes }
) {
validateParams(
[
'title',
'fk_relation_column_id',
'fk_rollup_column_id',
'rollup_function',
],
payload
);
const relation = await (
await Column.get({
colId: (payload as RollupColumnReqType).fk_relation_column_id,
})
).getColOptions<LinkToAnotherRecordType>();
if (!relation) {
throw new Error('Relation column not found');
}
let relatedColumn: Column;
switch (relation.type) {
case 'hm':
relatedColumn = await Column.get({
colId: relation.fk_child_column_id,
});
break;
case 'mm':
case 'bt':
relatedColumn = await Column.get({
colId: relation.fk_parent_column_id,
});
break;
}
const relatedTable = await relatedColumn.getModel();
if (
!(await relatedTable.getColumns()).find(
(c) => c.id === (payload as RollupColumnReqType).fk_rollup_column_id
)
)
throw new Error('Rollup column not found in related table');
}
async function validateLookupPayload(
payload: ColumnReqType & { uidt: UITypes }
) {
validateParams(
['title', 'fk_relation_column_id', 'fk_lookup_column_id'],
payload
);
const relation = await (
await Column.get({
colId: (payload as LookupColumnReqType).fk_relation_column_id,
})
).getColOptions<LinkToAnotherRecordType>();
if (!relation) {
throw new Error('Relation column not found');
}
let relatedColumn: Column;
switch (relation.type) {
case 'hm':
relatedColumn = await Column.get({
colId: relation.fk_child_column_id,
});
break;
case 'mm':
case 'bt':
relatedColumn = await Column.get({
colId: relation.fk_parent_column_id,
});
break;
}
const relatedTable = await relatedColumn.getModel();
if (
!(await relatedTable.getColumns()).find(
(c) => c.id === (payload as LookupColumnReqType).fk_lookup_column_id
)
)
throw new Error('Lookup column not found in related table');
}
export async function columnAdd( export async function columnAdd(
req: Request<any, any, ColumnReqType & { uidt: UITypes }>, req: Request<any, any, ColumnReqType & { uidt: UITypes }>,
res: Response<TableType> res: Response<TableType>
@ -153,49 +242,7 @@ export async function columnAdd(
switch (colBody.uidt) { switch (colBody.uidt) {
case UITypes.Rollup: case UITypes.Rollup:
{ {
validateParams( await validateRollupPayload(req.body);
[
'title',
'fk_relation_column_id',
'fk_rollup_column_id',
'rollup_function',
],
req.body
);
const relation = await (
await Column.get({
colId: (req.body as RollupColumnReqType).fk_relation_column_id,
})
).getColOptions<LinkToAnotherRecordType>();
if (!relation) {
throw new Error('Relation column not found');
}
let relatedColumn: Column;
switch (relation.type) {
case 'hm':
relatedColumn = await Column.get({
colId: relation.fk_child_column_id,
});
break;
case 'mm':
case 'bt':
relatedColumn = await Column.get({
colId: relation.fk_parent_column_id,
});
break;
}
const relatedTable = await relatedColumn.getModel();
if (
!(await relatedTable.getColumns()).find(
(c) =>
c.id === (req.body as RollupColumnReqType).fk_rollup_column_id
)
)
throw new Error('Rollup column not found in related table');
await Column.insert({ await Column.insert({
...colBody, ...colBody,
@ -205,44 +252,7 @@ export async function columnAdd(
break; break;
case UITypes.Lookup: case UITypes.Lookup:
{ {
validateParams( await validateLookupPayload(req.body);
['title', 'fk_relation_column_id', 'fk_lookup_column_id'],
req.body
);
const relation = await (
await Column.get({
colId: (req.body as LookupColumnReqType).fk_relation_column_id,
})
).getColOptions<LinkToAnotherRecordType>();
if (!relation) {
throw new Error('Relation column not found');
}
let relatedColumn: Column;
switch (relation.type) {
case 'hm':
relatedColumn = await Column.get({
colId: relation.fk_child_column_id,
});
break;
case 'mm':
case 'bt':
relatedColumn = await Column.get({
colId: relation.fk_parent_column_id,
});
break;
}
const relatedTable = await relatedColumn.getModel();
if (
!(await relatedTable.getColumns()).find(
(c) =>
c.id === (req.body as LookupColumnReqType).fk_lookup_column_id
)
)
throw new Error('Lookup column not found in related table');
await Column.insert({ await Column.insert({
...colBody, ...colBody,
@ -753,6 +763,30 @@ export async function columnSetAsPrimary(req: Request, res: Response) {
res.json(await Model.updatePrimaryColumn(column.fk_model_id, column.id)); res.json(await Model.updatePrimaryColumn(column.fk_model_id, column.id));
} }
const isAllPropsPresent = (obj: Record<string, any>, props: string[]) => {
return props.every((prop) => obj[prop]);
};
async function updateRollupOrLookup(colBody: any, column: Column<any>) {
if (
UITypes.Lookup === column.uidt &&
isAllPropsPresent(colBody, ['fk_lookup_column_id', 'fk_relation_column_id'])
) {
await validateLookupPayload(colBody);
await Column.update(column.id, colBody);
} else if (
UITypes.Rollup === column.uidt &&
isAllPropsPresent(colBody, [
'fk_relation_column_id',
'fk_rollup_column_id',
'rollup_function',
])
) {
await validateRollupPayload(colBody);
await Column.update(column.id, colBody);
}
}
export async function columnUpdate(req: Request, res: Response<TableType>) { export async function columnUpdate(req: Request, res: Response<TableType>) {
const column = await Column.get({ colId: req.params.columnId }); const column = await Column.get({ colId: req.params.columnId });
@ -824,6 +858,7 @@ export async function columnUpdate(req: Request, res: Response<TableType>) {
title: colBody.title, title: colBody.title,
}); });
} }
await updateRollupOrLookup(colBody, column);
} else { } else {
NcError.notImplemented( NcError.notImplemented(
`Updating ${colBody.uidt} => ${colBody.uidt} is not implemented` `Updating ${colBody.uidt} => ${colBody.uidt} is not implemented`

Loading…
Cancel
Save