From 0779a69cae52ba4ed9e88a626d8beb8507d96f4a Mon Sep 17 00:00:00 2001 From: Wing-Kam Wong Date: Mon, 14 Nov 2022 11:50:13 +0800 Subject: [PATCH 01/52] fix(nc-gui): reduce of empty array with no initial value --- packages/nc-gui/utils/parsers/CSVTemplateAdapter.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/nc-gui/utils/parsers/CSVTemplateAdapter.ts b/packages/nc-gui/utils/parsers/CSVTemplateAdapter.ts index 01390ecb4e..1e1c50b8de 100644 --- a/packages/nc-gui/utils/parsers/CSVTemplateAdapter.ts +++ b/packages/nc-gui/utils/parsers/CSVTemplateAdapter.ts @@ -179,8 +179,10 @@ export default class CSVTemplateAdapter { ) { this.tables[tableIdx].columns[columnIdx].uidt = UITypes.Date // take the date format with the max occurrence - this.tables[tableIdx].columns[columnIdx].meta.date_format = - Object.keys(dateFormat).reduce((x, y) => (dateFormat[x] > dateFormat[y] ? x : y)) || 'YYYY/MM/DD' + const objKeys = Object.keys(dateFormat) + this.tables[tableIdx].columns[columnIdx].meta.date_format = objKeys.length + ? objKeys.reduce((x, y) => (dateFormat[x] > dateFormat[y] ? x : y)) + : 'YYYY/MM/DD' } else { // Datetime this.tables[tableIdx].columns[columnIdx].uidt = uidt From b802aa550852bf3143e00a38d36a76267f1e4d4d Mon Sep 17 00:00:00 2001 From: Wing-Kam Wong Date: Mon, 14 Nov 2022 16:45:03 +0800 Subject: [PATCH 02/52] fix(nc-gui): avoid keeping unnecessary props when switching column type --- .../nc-gui/composables/useColumnCreateStore.ts | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/packages/nc-gui/composables/useColumnCreateStore.ts b/packages/nc-gui/composables/useColumnCreateStore.ts index 9816b4e183..922b12464c 100644 --- a/packages/nc-gui/composables/useColumnCreateStore.ts +++ b/packages/nc-gui/composables/useColumnCreateStore.ts @@ -97,7 +97,19 @@ const [useProvideColumnCreateStore, useColumnCreateStore] = createInjectionState const onUidtOrIdTypeChange = () => { const colProp = sqlUi.value.getDataTypeForUiType(formState.value as { uidt: UITypes }, idType ?? undefined) formState.value = { - ...formState.value, + ...(!isEdit.value && { + // only take title, column_name and uidt when creating a column + // to avoid the extra props from being taken (e.g. SingleLineText -> LTAR -> SingleLineText) + // to mess up the column creation + title: formState.value.title, + column_name: formState.value.column_name, + uidt: formState.value.uidt, + }), + ...(isEdit.value && { + // take the existing formState.value when editing a column + // LTAR is not available in this case + ...formState.value, + }), meta: {}, rqd: false, pk: false, From c91c0edefe88344746d7638b75cd8a4569e585a6 Mon Sep 17 00:00:00 2001 From: Wing-Kam Wong Date: Sat, 19 Nov 2022 16:46:36 +0800 Subject: [PATCH 03/52] fix(nocodb): remove ignoreFilterSort condition for applyPaginate and rename to ignoreViewFilterAndSort --- .../sql-data-mapper/lib/sql/BaseModelSqlv2.ts | 21 +++++++++++-------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/BaseModelSqlv2.ts b/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/BaseModelSqlv2.ts index 5c07bb1e2e..6b31c79d9b 100644 --- a/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/BaseModelSqlv2.ts +++ b/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/BaseModelSqlv2.ts @@ -175,7 +175,7 @@ class BaseModelSqlv2 { sortArr?: Sort[]; sort?: string | string[]; } = {}, - ignoreFilterSort = false + ignoreViewFilterAndSort = false ): Promise { const { where, ...rest } = this._getListArgs(args as any); @@ -189,7 +189,7 @@ class BaseModelSqlv2 { let sorts = extractSortsObject(rest?.sort, aliasColObjMap); const filterObj = extractFilterFromXwhere(where, aliasColObjMap); // todo: replace with view id - if (!ignoreFilterSort && this.viewId) { + if (!ignoreViewFilterAndSort && this.viewId) { await conditionV2( [ new Filter({ @@ -249,7 +249,7 @@ class BaseModelSqlv2 { qb.orderBy('created_at'); } - if (!ignoreFilterSort) applyPaginate(qb, rest); + applyPaginate(qb, rest); const proto = await this.getProto(); const data = await this.extractRawQueryAndExec(qb); @@ -261,7 +261,7 @@ class BaseModelSqlv2 { public async count( args: { where?: string; limit?; filterArr?: Filter[] } = {}, - ignoreFilterSort = false + ignoreViewFilterAndSort = false ): Promise { await this.model.getColumns(); const { where } = this._getListArgs(args); @@ -272,7 +272,7 @@ class BaseModelSqlv2 { const aliasColObjMap = await this.model.getAliasColObjMap(); const filterObj = extractFilterFromXwhere(where, aliasColObjMap); - if (!ignoreFilterSort && this.viewId) { + if (!ignoreViewFilterAndSort && this.viewId) { await conditionV2( [ new Filter({ @@ -2474,7 +2474,7 @@ class BaseModelSqlv2 { public async groupedList( args: { groupColumnId: string; - ignoreFilterSort?: boolean; + ignoreViewFilterAndSort?: boolean; options?: (string | number | null | boolean)[]; } & Partial ): Promise< @@ -2527,7 +2527,7 @@ class BaseModelSqlv2 { let sorts = extractSortsObject(args?.sort, aliasColObjMap); const filterObj = extractFilterFromXwhere(where, aliasColObjMap); // todo: replace with view id - if (!args.ignoreFilterSort && this.viewId) { + if (!args.ignoreViewFilterAndSort && this.viewId) { await conditionV2( [ new Filter({ @@ -2640,7 +2640,10 @@ class BaseModelSqlv2 { } public async groupedListCount( - args: { groupColumnId: string; ignoreFilterSort?: boolean } & XcFilter + args: { + groupColumnId: string; + ignoreViewFilterAndSort?: boolean; + } & XcFilter ) { const column = await this.model .getColumns() @@ -2659,7 +2662,7 @@ class BaseModelSqlv2 { const filterObj = extractFilterFromXwhere(args.where, aliasColObjMap); // todo: replace with view id - if (!args.ignoreFilterSort && this.viewId) { + if (!args.ignoreViewFilterAndSort && this.viewId) { await conditionV2( [ new Filter({ From 501292cead98e472be6eea204edfb19bfcd68eb0 Mon Sep 17 00:00:00 2001 From: Wing-Kam Wong Date: Sat, 19 Nov 2022 16:47:19 +0800 Subject: [PATCH 04/52] fix(nc-gui): query field returns empty result with non-zero offset --- packages/nc-gui/composables/useViewData.ts | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/packages/nc-gui/composables/useViewData.ts b/packages/nc-gui/composables/useViewData.ts index 706ab27c57..c4e5bedbff 100644 --- a/packages/nc-gui/composables/useViewData.ts +++ b/packages/nc-gui/composables/useViewData.ts @@ -189,6 +189,14 @@ export function useViewData( : await fetchSharedViewData({ sortsArr: sorts.value, filtersArr: nestedFilters.value }) formattedData.value = formatData(response.list) paginationData.value = response.pageInfo + + // to cater the case like when querying with a non-zero offset + // the result page may point to the target page where the actual returned data don't display on + const expectedPage = Math.ceil(paginationData.value.totalRows! / paginationData.value.pageSize!) + if (Math.max(1, expectedPage) < paginationData.value.page!) { + await changePage(expectedPage) + } + if (viewMeta.value?.type === ViewTypes.GRID) { await loadAggCommentsCount() } From 7c615768b6ea233a4cd08ee9459794b5cd60db94 Mon Sep 17 00:00:00 2001 From: Wing-Kam Wong Date: Sat, 19 Nov 2022 19:10:44 +0800 Subject: [PATCH 05/52] feat(nc-gui): add save & exit and save & stay --- packages/nc-gui/lang/en.json | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/nc-gui/lang/en.json b/packages/nc-gui/lang/en.json index 08db4c8610..bd19e8ad4a 100644 --- a/packages/nc-gui/lang/en.json +++ b/packages/nc-gui/lang/en.json @@ -368,6 +368,8 @@ "setPrimary": "Set as Primary value", "addRow": "Add new row", "saveRow": "Save row", + "saveAndExit": "Save & Exit", + "saveAndStay": "Save & Stay", "insertRow": "Insert New Row", "deleteRow": "Delete Row", "deleteSelectedRow": "Delete Selected Rows", From 633fec95f92ea19ac7564ff8069d507b876dd0ae Mon Sep 17 00:00:00 2001 From: Wing-Kam Wong Date: Sat, 19 Nov 2022 19:11:20 +0800 Subject: [PATCH 06/52] feat(nc-gui): remove important on py-0 --- packages/nc-gui/assets/style.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/nc-gui/assets/style.scss b/packages/nc-gui/assets/style.scss index 7e3d0f5cd5..76489a82dd 100644 --- a/packages/nc-gui/assets/style.scss +++ b/packages/nc-gui/assets/style.scss @@ -261,7 +261,7 @@ a { } .ant-dropdown-menu-item, .ant-menu-item { - @apply !py-0 active:(ring ring-accent ring-opacity-100); + @apply py-0 active:(ring ring-accent ring-opacity-100); } .ant-dropdown-menu-title-content, From d57d722566d619bfc52663532870149ff0fde467 Mon Sep 17 00:00:00 2001 From: Wing-Kam Wong Date: Sat, 19 Nov 2022 19:13:06 +0800 Subject: [PATCH 07/52] feat(nc-gui): add MdiCancel, MdiContentSaveEdit & ADropdownButton --- packages/nc-gui/components.d.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/nc-gui/components.d.ts b/packages/nc-gui/components.d.ts index 1be206af09..681ddee0f7 100644 --- a/packages/nc-gui/components.d.ts +++ b/packages/nc-gui/components.d.ts @@ -24,6 +24,7 @@ declare module '@vue/runtime-core' { ADivider: typeof import('ant-design-vue/es')['Divider'] ADrawer: typeof import('ant-design-vue/es')['Drawer'] ADropdown: typeof import('ant-design-vue/es')['Dropdown'] + ADropdownButton: typeof import('ant-design-vue/es')['DropdownButton'] AEmpty: typeof import('ant-design-vue/es')['Empty'] AForm: typeof import('ant-design-vue/es')['Form'] AFormItem: typeof import('ant-design-vue/es')['FormItem'] @@ -126,6 +127,7 @@ declare module '@vue/runtime-core' { MdiBugOutline: typeof import('~icons/mdi/bug-outline')['default'] MdiCalculator: typeof import('~icons/mdi/calculator')['default'] MdiCalendarMonth: typeof import('~icons/mdi/calendar-month')['default'] + MdiCancel: typeof import('~icons/mdi/cancel')['default'] MdiCardsHeart: typeof import('~icons/mdi/cards-heart')['default'] MdiCellphoneMessage: typeof import('~icons/mdi/cellphone-message')['default'] MdiChat: typeof import('~icons/mdi/chat')['default'] @@ -143,6 +145,7 @@ declare module '@vue/runtime-core' { MdiCommentTextOutline: typeof import('~icons/mdi/comment-text-outline')['default'] MdiContentCopy: typeof import('~icons/mdi/content-copy')['default'] MdiContentSave: typeof import('~icons/mdi/content-save')['default'] + MdiContentSaveEdit: typeof import('~icons/mdi/content-save-edit')['default'] MdiCurrencyUsd: typeof import('~icons/mdi/currency-usd')['default'] MdiDatabaseOutline: typeof import('~icons/mdi/database-outline')['default'] MdiDatabaseSync: typeof import('~icons/mdi/database-sync')['default'] From f9250b7c95c1125585d9b6c89db25ffae1bf6080 Mon Sep 17 00:00:00 2001 From: Wing-Kam Wong Date: Sat, 19 Nov 2022 19:13:28 +0800 Subject: [PATCH 08/52] feat(nc-gui): add save and exit / stay logic --- .../smartsheet/expanded-form/Header.vue | 42 ++++++++++++++++--- 1 file changed, 36 insertions(+), 6 deletions(-) diff --git a/packages/nc-gui/components/smartsheet/expanded-form/Header.vue b/packages/nc-gui/components/smartsheet/expanded-form/Header.vue index 8519599e32..9e67e7fb98 100644 --- a/packages/nc-gui/components/smartsheet/expanded-form/Header.vue +++ b/packages/nc-gui/components/smartsheet/expanded-form/Header.vue @@ -25,6 +25,8 @@ const { isUIAllowed } = useUIPermission() const reloadTrigger = inject(ReloadRowDataHookInj, createEventHook()) +const saveRowAndStay = ref(0) + const save = async () => { if (isNew.value) { const data = await _save(state.value) @@ -34,6 +36,9 @@ const save = async () => { await _save() reloadTrigger?.trigger() } + if (!saveRowAndStay.value) { + emit('cancel') + } } // todo: accept as a prop / inject @@ -101,14 +106,39 @@ const copyRecordUrl = () => { - - {{ $t('general.cancel') }} +
+ + + {{ $t('general.cancel') }} +
- - - {{ $t('activity.saveRow') }} - + + +
+ + {{ $t('activity.saveAndExit') }} +
+
+ + {{ $t('activity.saveAndStay') }} +
+
From 6e153b7bfcf9ece5a1702016f19563d7411de9a3 Mon Sep 17 00:00:00 2001 From: Wing-Kam Wong Date: Sat, 19 Nov 2022 23:18:01 +0800 Subject: [PATCH 09/52] test(playwright): update Save Row button text --- tests/playwright/pages/Dashboard/ExpandedForm/index.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/playwright/pages/Dashboard/ExpandedForm/index.ts b/tests/playwright/pages/Dashboard/ExpandedForm/index.ts index 22dc0bfe03..df73b29a4a 100644 --- a/tests/playwright/pages/Dashboard/ExpandedForm/index.ts +++ b/tests/playwright/pages/Dashboard/ExpandedForm/index.ts @@ -57,7 +57,7 @@ export class ExpandedFormPage extends BasePage { }: { waitForRowsData?: boolean; } = {}) { - const saveRowAction = this.get().locator('button:has-text("Save Row")').click(); + const saveRowAction = this.get().locator('button:has-text("Save & Exit")').click(); if (waitForRowsData) { await this.waitForResponse({ uiAction: saveRowAction, @@ -104,9 +104,9 @@ export class ExpandedFormPage extends BasePage { async validateRoleAccess(param: { role: string }) { if (param.role === 'commenter' || param.role === 'viewer') { - await expect(await this.get().locator('button:has-text("Save Row")')).toBeDisabled(); + await expect(await this.get().locator('button:has-text("Save & Exit")')).toBeDisabled(); } else { - await expect(await this.get().locator('button:has-text("Save Row")')).toBeEnabled(); + await expect(await this.get().locator('button:has-text("Save & Exit")')).toBeEnabled(); } if (param.role === 'viewer') { await expect(await this.toggleCommentsButton).toHaveCount(0); From 874a3f122ba5206973f1ad6b20bcfad88a12c534 Mon Sep 17 00:00:00 2001 From: Wing-Kam Wong Date: Sun, 20 Nov 2022 09:57:35 +0800 Subject: [PATCH 10/52] feat(nc-gui): rename cancel button to close --- .../nc-gui/components/smartsheet/expanded-form/Header.vue | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/nc-gui/components/smartsheet/expanded-form/Header.vue b/packages/nc-gui/components/smartsheet/expanded-form/Header.vue index 9e67e7fb98..0517ee6c54 100644 --- a/packages/nc-gui/components/smartsheet/expanded-form/Header.vue +++ b/packages/nc-gui/components/smartsheet/expanded-form/Header.vue @@ -107,9 +107,9 @@ const copyRecordUrl = () => {
- - - {{ $t('general.cancel') }} + + + {{ $t('general.close') }}
From 2fab4c46328e8e719f99aae72afbd78a5e16d0c0 Mon Sep 17 00:00:00 2001 From: Pranav C Date: Sun, 20 Nov 2022 15:59:26 +0530 Subject: [PATCH 11/52] fix(gui): miscellaneous ui fixes and improvement Signed-off-by: Pranav C --- packages/nc-gui/components.d.ts | 1 + .../nc-gui/components/dlg/TableCreate.vue | 8 +- .../smartsheet/column/EditOrAdd.vue | 7 ++ .../smartsheet/column/SelectOptions.vue | 4 +- .../smartsheet/toolbar/ShareView.vue | 102 ++++++++---------- .../tabs/auth/user-management/UsersModal.vue | 6 ++ .../nc-gui/components/virtual-cell/Lookup.vue | 2 +- .../composables/useMultiSelect/index.ts | 1 + .../form/[viewId]/index/survey.vue | 4 +- .../sql-data-mapper/lib/sql/BaseModelSqlv2.ts | 4 +- 10 files changed, 71 insertions(+), 68 deletions(-) diff --git a/packages/nc-gui/components.d.ts b/packages/nc-gui/components.d.ts index 1be206af09..3b0dd76f2f 100644 --- a/packages/nc-gui/components.d.ts +++ b/packages/nc-gui/components.d.ts @@ -200,6 +200,7 @@ declare module '@vue/runtime-core' { MdiPlus: typeof import('~icons/mdi/plus')['default'] MdiPlusCircleOutline: typeof import('~icons/mdi/plus-circle-outline')['default'] MdiPlusOutline: typeof import('~icons/mdi/plus-outline')['default'] + MdiPlusThick: typeof import('~icons/mdi/plus-thick')['default'] MdiReddit: typeof import('~icons/mdi/reddit')['default'] MdiRefresh: typeof import('~icons/mdi/refresh')['default'] MdiReload: typeof import('~icons/mdi/reload')['default'] diff --git a/packages/nc-gui/components/dlg/TableCreate.vue b/packages/nc-gui/components/dlg/TableCreate.vue index 7c36fa06e7..46fcb06b87 100644 --- a/packages/nc-gui/components/dlg/TableCreate.vue +++ b/packages/nc-gui/components/dlg/TableCreate.vue @@ -1,5 +1,5 @@ diff --git a/packages/nc-gui/components/smartsheet/column/EditOrAdd.vue b/packages/nc-gui/components/smartsheet/column/EditOrAdd.vue index 5acda92b36..0eb697dc36 100644 --- a/packages/nc-gui/components/smartsheet/column/EditOrAdd.vue +++ b/packages/nc-gui/components/smartsheet/column/EditOrAdd.vue @@ -1,4 +1,5 @@