From 7b2a02d580ba2f70006cefb6f4ed479ee31b7a15 Mon Sep 17 00:00:00 2001 From: Pranav C Date: Wed, 21 Jun 2023 12:07:43 +0530 Subject: [PATCH 1/7] fix: do relation delete only for non-virtual relation Signed-off-by: Pranav C --- packages/nocodb/src/meta/meta.service.ts | 2 +- packages/nocodb/src/services/columns.service.ts | 10 +++++++--- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/packages/nocodb/src/meta/meta.service.ts b/packages/nocodb/src/meta/meta.service.ts index 565b921b42..cf8fbb2938 100644 --- a/packages/nocodb/src/meta/meta.service.ts +++ b/packages/nocodb/src/meta/meta.service.ts @@ -619,7 +619,7 @@ export class MetaService { offset?: number; xcCondition?; fields?: string[]; - orderBy: { [key: string]: 'asc' | 'desc' }; + orderBy?: { [key: string]: 'asc' | 'desc' }; }, ): Promise { const query = this.knexConnection(target); diff --git a/packages/nocodb/src/services/columns.service.ts b/packages/nocodb/src/services/columns.service.ts index f1c8a81620..3c73a88770 100644 --- a/packages/nocodb/src/services/columns.service.ts +++ b/packages/nocodb/src/services/columns.service.ts @@ -1216,6 +1216,7 @@ export class ColumnsService { childColumn: mmParentCol, base, ncMeta, + virtual: !!relationColOpt.virtual, }, true, ); @@ -1230,6 +1231,7 @@ export class ColumnsService { childColumn: mmChildCol, base, ncMeta, + virtual: !!relationColOpt.virtual, }, true, ); @@ -1387,6 +1389,7 @@ export class ColumnsService { parentTable, sqlMgr, ncMeta = Noco.ncMeta, + virtual, }: { relationColOpt: LinkToAnotherRecordColumn; base: Base; @@ -1396,6 +1399,7 @@ export class ColumnsService { parentTable: Model; sqlMgr: SqlMgrv2; ncMeta?: MetaService; + virtual?: boolean; }, ignoreFkDelete = false, ) => { @@ -1424,7 +1428,7 @@ export class ColumnsService { foreignKeyName = relationColOpt.fk_index_name; } - if (!relationColOpt?.virtual) { + if (!relationColOpt?.virtual && !virtual) { // todo: handle relation delete exception try { await sqlMgr.sqlOpPlus(base, 'relationDelete', { @@ -1435,7 +1439,7 @@ export class ColumnsService { foreignKeyName, }); } catch (e) { - console.log(e); + console.log(e.message); } } @@ -1481,7 +1485,7 @@ export class ColumnsService { if (index.cn !== childColumn.column_name) continue; await sqlMgr.sqlOpPlus(base, 'indexDelete', { - ...index, + ...index, tn: cTable.table_name, columns: [childColumn.column_name], indexName: index.index_name, From 9ddabcc54e5fa0129151aa91aaa17d1e4f83be6d Mon Sep 17 00:00:00 2001 From: Pranav C Date: Wed, 21 Jun 2023 12:12:49 +0530 Subject: [PATCH 2/7] fix: handle null case Signed-off-by: Pranav C --- packages/nocodb/src/models/View.ts | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/packages/nocodb/src/models/View.ts b/packages/nocodb/src/models/View.ts index 187a0ee52d..79eda3747d 100644 --- a/packages/nocodb/src/models/View.ts +++ b/packages/nocodb/src/models/View.ts @@ -127,8 +127,10 @@ export default class View implements ViewType { )); if (!view) { view = await ncMeta.metaGet2(null, null, MetaTable.VIEWS, viewId); - view.meta = parseMetaProp(view); - await NocoCache.set(`${CacheScope.VIEW}:${view.id}`, view); + if (view) { + view.meta = parseMetaProp(view); + await NocoCache.set(`${CacheScope.VIEW}:${view.id}`, view); + } } return view && new View(view); @@ -1273,7 +1275,7 @@ export default class View implements ViewType { ); } - async delete(ncMeta = Noco.ncMeta){ + async delete(ncMeta = Noco.ncMeta) { await View.delete(this.id, ncMeta); } From c21c38bdbde6a5ec1dd00db5ce119491d5785565 Mon Sep 17 00:00:00 2001 From: Pranav C Date: Wed, 21 Jun 2023 12:48:16 +0530 Subject: [PATCH 3/7] fix: handle null case Signed-off-by: Pranav C --- packages/nocodb/src/models/Model.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/nocodb/src/models/Model.ts b/packages/nocodb/src/models/Model.ts index 8750ef7c9f..7caa3bef62 100644 --- a/packages/nocodb/src/models/Model.ts +++ b/packages/nocodb/src/models/Model.ts @@ -293,9 +293,9 @@ export default class Model implements TableType { )); if (!modelData) { modelData = await ncMeta.metaGet2(null, null, MetaTable.MODELS, k); - modelData.meta = parseMetaProp(modelData); } if (modelData) { + modelData.meta = parseMetaProp(modelData); await NocoCache.set(`${CacheScope.MODEL}:${modelData.id}`, modelData); return new Model(modelData); } From e1fd58b1f6d6d17e1c1993ae7bae768776fa8482 Mon Sep 17 00:00:00 2001 From: Pranav C Date: Wed, 21 Jun 2023 12:55:18 +0530 Subject: [PATCH 4/7] fix: handle null cases everywhere Signed-off-by: Pranav C --- packages/nocodb/src/models/Model.ts | 6 ++++-- packages/nocodb/src/models/View.ts | 6 ++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/packages/nocodb/src/models/Model.ts b/packages/nocodb/src/models/Model.ts index 7caa3bef62..9ed0b189ca 100644 --- a/packages/nocodb/src/models/Model.ts +++ b/packages/nocodb/src/models/Model.ts @@ -327,8 +327,10 @@ export default class Model implements TableType { table_name, }, ); - modelData.meta = parseMetaProp(modelData); - await NocoCache.set(`${CacheScope.MODEL}:${modelData.id}`, modelData); + if (modelData) { + modelData.meta = parseMetaProp(modelData); + await NocoCache.set(`${CacheScope.MODEL}:${modelData.id}`, modelData); + } // modelData.filters = await Filter.getFilterObject({ // viewId: modelData.id // }); diff --git a/packages/nocodb/src/models/View.ts b/packages/nocodb/src/models/View.ts index 79eda3747d..9a4fd88f2f 100644 --- a/packages/nocodb/src/models/View.ts +++ b/packages/nocodb/src/models/View.ts @@ -207,8 +207,10 @@ export default class View implements ViewType { }, null, ); - view.meta = parseMetaProp(view); - await NocoCache.set(`${CacheScope.VIEW}:${fk_model_id}:default`, view); + if (view) { + view.meta = parseMetaProp(view); + await NocoCache.set(`${CacheScope.VIEW}:${fk_model_id}:default`, view); + } } return view && new View(view); } From 52ee55249424e4cc374d07efa3e1782ed4cc5ab5 Mon Sep 17 00:00:00 2001 From: Pranav C Date: Wed, 21 Jun 2023 15:29:46 +0530 Subject: [PATCH 5/7] fix: handle if table not found Signed-off-by: Pranav C --- packages/nocodb/src/services/tables.service.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/nocodb/src/services/tables.service.ts b/packages/nocodb/src/services/tables.service.ts index ae89adb87b..299291ec41 100644 --- a/packages/nocodb/src/services/tables.service.ts +++ b/packages/nocodb/src/services/tables.service.ts @@ -247,6 +247,10 @@ export class TablesService { id: param.tableId, }); + if (!table) { + NcError.notFound('Table not found'); + } + // todo: optimise const viewList = ( await this.xcVisibilityMetaGet(table.project_id, [table]) From e22a3cd19c91c7cfc1a0f47958707ac9e916a3f6 Mon Sep 17 00:00:00 2001 From: Pranav C Date: Wed, 21 Jun 2023 16:38:43 +0530 Subject: [PATCH 6/7] fix: add an option skip meta get if missing in cache Signed-off-by: Pranav C --- packages/nc-gui/components/smartsheet/Grid.vue | 4 ++-- packages/nc-gui/composables/useMetas.ts | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/packages/nc-gui/components/smartsheet/Grid.vue b/packages/nc-gui/components/smartsheet/Grid.vue index 5a4595e7bb..1940aada59 100644 --- a/packages/nc-gui/components/smartsheet/Grid.vue +++ b/packages/nc-gui/components/smartsheet/Grid.vue @@ -768,7 +768,7 @@ onBeforeUnmount(async () => { const viewMetaValue = view.value const dataValue = data.value if (viewMetaValue) { - getMeta(viewMetaValue.fk_model_id).then((res) => { + getMeta(viewMetaValue.fk_model_id, false, true).then((res) => { const metaValue = res if (!metaValue) return saveOrUpdateRecords({ @@ -815,7 +815,7 @@ watch( switchingTab.value = true // whenever tab changes or view changes save any unsaved data if (old?.id) { - const oldMeta = await getMeta(old.fk_model_id!) + const oldMeta = await getMeta(old.fk_model_id!, false, true) if (oldMeta) { await saveOrUpdateRecords({ viewMetaValue: old, diff --git a/packages/nc-gui/composables/useMetas.ts b/packages/nc-gui/composables/useMetas.ts index 72cde33128..31f7931519 100644 --- a/packages/nc-gui/composables/useMetas.ts +++ b/packages/nc-gui/composables/useMetas.ts @@ -26,7 +26,7 @@ export function useMetas() { } // todo: this needs a proper refactor, arbitrary waiting times are usually not a good idea - const getMeta = async (tableIdOrTitle: string, force = false): Promise => { + const getMeta = async (tableIdOrTitle: string, force = false, skipIfCacheMiss = false): Promise => { if (!tableIdOrTitle) return null /** wait until loading is finished if requesting same meta */ if (!force && loadingState.value[tableIdOrTitle]) { @@ -58,6 +58,7 @@ export function useMetas() { return metas.value[tableIdOrTitle] } } + if (skipIfCacheMiss) return null loadingState.value[tableIdOrTitle] = true From 14757d6b0d4fc4069857b63c83ee9af88562de74 Mon Sep 17 00:00:00 2001 From: Pranav C Date: Wed, 21 Jun 2023 16:40:22 +0530 Subject: [PATCH 7/7] chore: lint Signed-off-by: Pranav C --- .../nc-gui/components/cell/MultiSelect.vue | 4 +-- .../nc-gui/components/cell/SingleSelect.vue | 6 ++--- .../nc-gui/components/dashboard/TreeView.vue | 2 +- .../nc-gui/components/smartsheet/Form.vue | 11 +++++--- .../nc-gui/components/smartsheet/Grid.vue | 2 +- .../column/LinkedToAnotherRecordOptions.vue | 8 +++--- .../composables/useColumnCreateStore.ts | 2 +- .../form/[viewId]/index/index.vue | 10 +++---- .../form/[viewId]/index/survey.vue | 12 ++++----- .../nocodb/src/db/sql-mgr/v2/ProjectMgrv2.ts | 27 ++++++++++--------- .../nocodb/src/services/tables.service.ts | 1 - .../src/services/users/users.service.ts | 5 +++- 12 files changed, 48 insertions(+), 42 deletions(-) diff --git a/packages/nc-gui/components/cell/MultiSelect.vue b/packages/nc-gui/components/cell/MultiSelect.vue index e6f8570d68..e2569578cc 100644 --- a/packages/nc-gui/components/cell/MultiSelect.vue +++ b/packages/nc-gui/components/cell/MultiSelect.vue @@ -8,6 +8,7 @@ import { ActiveCellInj, CellClickHookInj, ColumnInj, + EditModeInj, IsKanbanInj, ReadonlyInj, RowHeightInj, @@ -27,7 +28,6 @@ import { useRoles, useSelectedCellKeyupListener, watch, - EditModeInj } from '#imports' import MdiCloseCircle from '~icons/mdi/close-circle' @@ -101,7 +101,7 @@ const isOptionMissing = computed(() => { const hasEditRoles = computed(() => hasRole('owner', true) || hasRole('creator', true) || hasRole('editor', true)) -const editAllowed = computed(() => (hasEditRoles.value || isForm.value) && (active.value)) +const editAllowed = computed(() => (hasEditRoles.value || isForm.value) && active.value) const vModel = computed({ get: () => { diff --git a/packages/nc-gui/components/cell/SingleSelect.vue b/packages/nc-gui/components/cell/SingleSelect.vue index 1086ba0993..3b9dafbadb 100644 --- a/packages/nc-gui/components/cell/SingleSelect.vue +++ b/packages/nc-gui/components/cell/SingleSelect.vue @@ -8,6 +8,7 @@ import { ActiveCellInj, CellClickHookInj, ColumnInj, + EditModeInj, IsFormInj, IsKanbanInj, ReadonlyInj, @@ -23,7 +24,6 @@ import { useRoles, useSelectedCellKeyupListener, watch, - EditModeInj } from '#imports' interface Props { @@ -96,7 +96,7 @@ const isOptionMissing = computed(() => { const hasEditRoles = computed(() => hasRole('owner', true) || hasRole('creator', true) || hasRole('editor', true)) -const editAllowed = computed(() => (hasEditRoles.value || isForm.value) && (active.value)) +const editAllowed = computed(() => (hasEditRoles.value || isForm.value) && active.value) const vModel = computed({ get: () => tempSelectedOptState.value ?? modelValue, @@ -257,7 +257,7 @@ const selectedOpt = computed(() => { @@ -861,7 +863,8 @@ watch(view, (nextView) => { } } -.nc-form-help-text, .nc-input-required-error { +.nc-form-help-text, +.nc-input-required-error { max-width: 100%; word-break: break-all; white-space: pre-line; diff --git a/packages/nc-gui/components/smartsheet/Grid.vue b/packages/nc-gui/components/smartsheet/Grid.vue index 1940aada59..3673c818a3 100644 --- a/packages/nc-gui/components/smartsheet/Grid.vue +++ b/packages/nc-gui/components/smartsheet/Grid.vue @@ -746,7 +746,7 @@ const saveOrUpdateRecords = async (args: { metaValue?: TableType; viewMetaValue? async function reloadViewDataHandler(shouldShowLoading: boolean | void) { // save any unsaved data before reload - await saveOrUpdateRecords(); + await saveOrUpdateRecords() // set value if spinner should be hidden showLoading.value = !!shouldShowLoading diff --git a/packages/nc-gui/components/smartsheet/column/LinkedToAnotherRecordOptions.vue b/packages/nc-gui/components/smartsheet/column/LinkedToAnotherRecordOptions.vue index f285026379..368aebec78 100644 --- a/packages/nc-gui/components/smartsheet/column/LinkedToAnotherRecordOptions.vue +++ b/packages/nc-gui/components/smartsheet/column/LinkedToAnotherRecordOptions.vue @@ -129,11 +129,9 @@ const filterOption = (value: string, option: { key: string }) => option.key.toLo
- Virtual Relation - + Virtual Relation +
diff --git a/packages/nc-gui/composables/useColumnCreateStore.ts b/packages/nc-gui/composables/useColumnCreateStore.ts index a6b99847be..af638da694 100644 --- a/packages/nc-gui/composables/useColumnCreateStore.ts +++ b/packages/nc-gui/composables/useColumnCreateStore.ts @@ -291,7 +291,7 @@ const [useProvideColumnCreateStore, useColumnCreateStore] = createInjectionState isMssql, isPg, isMysql, - isXcdbBase + isXcdbBase, } }, ) diff --git a/packages/nc-gui/pages/[projectType]/form/[viewId]/index/index.vue b/packages/nc-gui/pages/[projectType]/form/[viewId]/index/index.vue index 795c0f7fe2..0572f7c77f 100644 --- a/packages/nc-gui/pages/[projectType]/form/[viewId]/index/index.vue +++ b/packages/nc-gui/pages/[projectType]/form/[viewId]/index/index.vue @@ -75,10 +75,7 @@ const onDecode = async (scannedCodeValue: string) => { class="color-transition relative flex flex-col justify-center gap-2 w-full max-w-[max(33%,600px)] m-auto py-4 pb-8 px-16 md:(bg-white dark:bg-slate-700 rounded-lg border-1 border-gray-200 shadow-xl)" >