Browse Source

Merge pull request #7478 from nocodb/nc-fix/ui-bug-fixes

Nc fix/UI bug fixes
pull/7510/head
Raju Udava 9 months ago committed by GitHub
parent
commit
7479d35d37
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 4
      packages/nc-gui/components/smartsheet/column/EditOrAdd.vue
  2. 2
      packages/nc-gui/components/smartsheet/grid/GroupByLabel.vue
  3. 2
      packages/nc-gui/components/virtual-cell/BelongsTo.vue
  4. 12
      packages/nocodb-sdk/src/lib/helperFunctions.ts
  5. 32
      packages/nocodb/src/models/Column.ts
  6. 16
      packages/nocodb/src/models/View.ts
  7. 1
      tests/playwright/pages/Dashboard/Grid/Column/index.ts
  8. 18
      tests/playwright/pages/Dashboard/common/Toolbar/Fields.ts
  9. 17
      tests/playwright/tests/db/columns/columnLinkToAnotherRecord.spec.ts
  10. 3
      tests/playwright/tests/db/columns/columnMenuOperations.spec.ts
  11. 3
      tests/playwright/tests/db/columns/columnRelationalExtendedTests.spec.ts
  12. 33
      tests/playwright/tests/db/features/metaLTAR.spec.ts
  13. 6
      tests/playwright/tests/db/views/viewGridShare.spec.ts

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

@ -1,6 +1,6 @@
<script lang="ts" setup> <script lang="ts" setup>
import type { ColumnReqType, ColumnType } from 'nocodb-sdk' import type { ColumnReqType, ColumnType } from 'nocodb-sdk'
import { UITypes, isLinksOrLTAR, isSystemColumn, isVirtualCol } from 'nocodb-sdk' import { UITypes, isLinksOrLTAR, isSelfReferencingTableColumn, isSystemColumn, isVirtualCol } from 'nocodb-sdk'
import { import {
IsFormInj, IsFormInj,
IsKanbanInj, IsKanbanInj,
@ -172,7 +172,7 @@ onMounted(() => {
if (formState.value.pk) { if (formState.value.pk) {
message.info(t('msg.info.editingPKnotSupported')) message.info(t('msg.info.editingPKnotSupported'))
emit('cancel') emit('cancel')
} else if (isSystemColumn(formState.value)) { } else if (isSystemColumn(formState.value) && !isSelfReferencingTableColumn(formState.value)) {
message.info(t('msg.info.editingSystemKeyNotSupported')) message.info(t('msg.info.editingSystemKeyNotSupported'))
emit('cancel') emit('cancel')
} }

2
packages/nc-gui/components/smartsheet/grid/GroupByLabel.vue

@ -14,7 +14,7 @@ provide(IsGroupByLabelInj, ref(true))
<template> <template>
<div class="pointer-events-none"> <div class="pointer-events-none">
<LazySmartsheetRow :row="{ row: { [column.title]: modelValue }, rowMeta: {} }"> <LazySmartsheetRow :row="{ row: { [column.title as string]: modelValue }, rowMeta: {} }">
<LazySmartsheetVirtualCell <LazySmartsheetVirtualCell
v-if="isVirtualCol(column)" v-if="isVirtualCol(column)"
:model-value="modelValue" :model-value="modelValue"

2
packages/nc-gui/components/virtual-cell/BelongsTo.vue

@ -99,7 +99,7 @@ watch([listItemsDlg], () => {
<template v-if="value && relatedTableDisplayValueProp"> <template v-if="value && relatedTableDisplayValueProp">
<VirtualCellComponentsItemChip <VirtualCellComponentsItemChip
:item="value" :item="value"
:value="value[relatedTableDisplayValueProp]" :value="!Array.isArray(value) && typeof value === 'object' ? value[relatedTableDisplayValueProp] : value"
:column="belongsToColumn" :column="belongsToColumn"
:show-unlink-button="true" :show-unlink-button="true"
@unlink="unlinkRef(value)" @unlink="unlinkRef(value)"

12
packages/nocodb-sdk/src/lib/helperFunctions.ts

@ -22,6 +22,17 @@ const isSystemColumn = (col): boolean =>
(col.pk && col.meta && col.meta.ag) || (col.pk && col.meta && col.meta.ag) ||
col.system); col.system);
const isSelfReferencingTableColumn = (col): boolean => {
return (
col &&
(col.uidt === UITypes.Links || col.uidt === UITypes.LinkToAnotherRecord) &&
(col?.fk_model_id || col?.colOptions?.fk_model_id) &&
col?.colOptions?.fk_related_model_id &&
(col?.fk_model_id || col?.colOptions?.fk_model_id) ===
col.colOptions.fk_related_model_id
);
};
const extractRolesObj = (roles: RolesType): RolesObj => { const extractRolesObj = (roles: RolesType): RolesObj => {
if (!roles) return null; if (!roles) return null;
@ -89,6 +100,7 @@ export {
getSystemColumnsIds, getSystemColumnsIds,
getSystemColumns, getSystemColumns,
isSystemColumn, isSystemColumn,
isSelfReferencingTableColumn,
extractRolesObj, extractRolesObj,
stringifyRolesObj, stringifyRolesObj,
getAvailableRollupForUiType, getAvailableRollupForUiType,

32
packages/nocodb/src/models/Column.ts

@ -197,7 +197,16 @@ export default class Column<T = any> implements ColumnType {
{ {
fk_column_id: row.id, fk_column_id: row.id,
fk_model_id: column.fk_model_id, fk_model_id: column.fk_model_id,
show: !column.view_id, column_show: {
show:
column.uidt === UITypes.LinkToAnotherRecord ||
(column.uidt === UITypes.Links &&
column.type === 'mm' &&
!column.view_id)
? false
: !column.view_id,
view_id: column.view_id,
},
column_order: column.column_order, column_order: column.column_order,
}, },
ncMeta, ncMeta,
@ -205,27 +214,6 @@ export default class Column<T = any> implements ColumnType {
await View.clearSingleQueryCache(column.fk_model_id); await View.clearSingleQueryCache(column.fk_model_id);
if (column.view_id) {
const viewColId = await View.getViewColumnId(
{
viewId: column.view_id,
colId: row.id,
},
ncMeta,
);
if (viewColId) {
await View.updateColumn(
column.view_id,
viewColId,
{
show: true,
},
ncMeta,
);
}
}
return col; return col;
} }

16
packages/nocodb/src/models/View.ts

@ -533,7 +533,10 @@ export default class View implements ViewType {
fk_column_id: any; fk_column_id: any;
fk_model_id: any; fk_model_id: any;
order?: number; order?: number;
show; column_show: {
show: boolean;
view_id?: any;
};
} & Pick<ColumnReqType, 'column_order'>, } & Pick<ColumnReqType, 'column_order'>,
ncMeta = Noco.ncMeta, ncMeta = Noco.ncMeta,
) { ) {
@ -541,12 +544,19 @@ export default class View implements ViewType {
fk_column_id: param.fk_column_id, fk_column_id: param.fk_column_id,
fk_model_id: param.fk_model_id, fk_model_id: param.fk_model_id,
order: param.order, order: param.order,
show: param.show, show: param.column_show.show,
}; };
const views = await this.list(param.fk_model_id, ncMeta); const views = await this.list(param.fk_model_id, ncMeta);
for (const view of views) { for (const view of views) {
const modifiedInsertObj = { ...insertObj, fk_view_id: view.id }; const modifiedInsertObj = {
...insertObj,
fk_view_id: view.id,
};
if (param.column_show?.view_id === view.id) {
modifiedInsertObj.show = true;
}
if (param.column_order?.view_id === view.id) { if (param.column_order?.view_id === view.id) {
modifiedInsertObj.order = param.column_order?.order; modifiedInsertObj.order = param.column_order?.order;

1
tests/playwright/pages/Dashboard/Grid/Column/index.ts

@ -455,6 +455,7 @@ export class ColumnPageObject extends BasePage {
// close sort menu // close sort menu
await this.grid.toolbar.clickSort(); await this.grid.toolbar.clickSort();
await this.rootPage.waitForTimeout(100);
} }
async resize(param: { src: string; dst: string }) { async resize(param: { src: string; dst: string }) {

18
tests/playwright/pages/Dashboard/common/Toolbar/Fields.ts

@ -19,16 +19,34 @@ export class ToolbarFieldsPage extends BasePage {
title, title,
isLocallySaved, isLocallySaved,
validateResponse = true, validateResponse = true,
checked,
}: { }: {
title: string; title: string;
isLocallySaved?: boolean; isLocallySaved?: boolean;
validateResponse?: boolean; validateResponse?: boolean;
checked?: boolean;
}) { }) {
await this.toolbar.clickFields(); await this.toolbar.clickFields();
// hack // hack
await this.rootPage.waitForTimeout(100); await this.rootPage.waitForTimeout(100);
if (checked !== undefined) {
// toggle only if input checked value is not equal to given checked value
await this.get()
.locator(`[data-testid="nc-fields-menu-${title}"]`)
.locator('.nc-switch')
.scrollIntoViewIfNeeded();
const isChecked = await this.get()
.locator(`[data-testid="nc-fields-menu-${title}"]`)
.locator('.nc-switch')
.isChecked();
if ((checked && isChecked) || (!checked && !isChecked)) {
await this.toolbar.clickFields();
return;
}
}
const toggleColumn = () => const toggleColumn = () =>
this.get().locator(`[data-testid="nc-fields-menu-${title}"]`).locator('.nc-switch').click(); this.get().locator(`[data-testid="nc-fields-menu-${title}"]`).locator('.nc-switch').click();

17
tests/playwright/tests/db/columns/columnLinkToAnotherRecord.spec.ts

@ -56,10 +56,16 @@ test.describe('LTAR create & update', () => {
}); });
// Sheet2 now has all 3 column categories : HM, BT, MM // Sheet2 now has all 3 column categories : HM, BT, MM
//
// Expanded form insert // Verify fields and toggle the visibility
await dashboard.grid.toolbar.clickFields();
for (const title of ['Sheet1', 'Sheet1s']) {
await dashboard.grid.toolbar.fields.verify({ title, checked: false });
await dashboard.grid.toolbar.fields.click({ title, isLocallySaved: false });
}
await dashboard.grid.toolbar.clickFields();
// Expanded form insert
await dashboard.grid.footbar.clickAddRecordFromForm(); await dashboard.grid.footbar.clickAddRecordFromForm();
await dashboard.expandedForm.fillField({ await dashboard.expandedForm.fillField({
columnTitle: 'Title', columnTitle: 'Title',
@ -100,6 +106,7 @@ test.describe('LTAR create & update', () => {
// Expand record insert // Expand record insert
await dashboard.grid.addNewRow({ index: 2, value: '2c-temp' }); await dashboard.grid.addNewRow({ index: 2, value: '2c-temp' });
await dashboard.grid.openExpandedRow({ index: 2 }); await dashboard.grid.openExpandedRow({ index: 2 });
await dashboard.expandedForm.fillField({ await dashboard.expandedForm.fillField({
columnTitle: 'Sheet1', columnTitle: 'Sheet1',
value: '1c', value: '1c',
@ -149,6 +156,12 @@ test.describe('LTAR create & update', () => {
await dashboard.closeTab({ title: 'Sheet2' }); await dashboard.closeTab({ title: 'Sheet2' });
await dashboard.treeView.openTable({ title: 'Sheet1' }); await dashboard.treeView.openTable({ title: 'Sheet1' });
// Verify fields and toggle the visibility
await dashboard.grid.toolbar.clickFields();
await dashboard.grid.toolbar.fields.verify({ title: 'Sheet2', checked: false });
await dashboard.grid.toolbar.fields.click({ title: 'Sheet2', isLocallySaved: false });
await dashboard.grid.toolbar.clickFields();
const expected2 = [ const expected2 = [
[['1 Sheet2'], ['1 Sheet2'], ['1 Sheet2']], [['1 Sheet2'], ['1 Sheet2'], ['1 Sheet2']],
[['1 Sheet2'], ['1 Sheet2'], ['1 Sheet2']], [['1 Sheet2'], ['1 Sheet2'], ['1 Sheet2']],

3
tests/playwright/tests/db/columns/columnMenuOperations.spec.ts

@ -85,6 +85,7 @@ test.describe('Column menu operations', () => {
insertAfterColumnTitle: 'Title', insertAfterColumnTitle: 'Title',
}); });
await dashboard.grid.toolbar.fields.toggle({ title: 'Actors', isLocallySaved: false, checked: true });
await dashboard.grid.column.create({ await dashboard.grid.column.create({
title: 'InsertAfterColumn1', title: 'InsertAfterColumn1',
type: 'SingleLineText', type: 'SingleLineText',
@ -104,6 +105,7 @@ test.describe('Column menu operations', () => {
isDisplayValue: true, isDisplayValue: true,
}); });
await dashboard.grid.toolbar.fields.toggle({ title: 'Actors', isLocallySaved: false, checked: true });
await dashboard.grid.column.create({ await dashboard.grid.column.create({
title: 'InsertBeforeColumn1', title: 'InsertBeforeColumn1',
type: 'SingleLineText', type: 'SingleLineText',
@ -121,6 +123,7 @@ test.describe('Column menu operations', () => {
isDisplayValue: true, isDisplayValue: true,
}); });
await dashboard.grid.toolbar.fields.toggle({ title: 'Actors', isLocallySaved: false, checked: true });
await dashboard.grid.column.hideColumn({ await dashboard.grid.column.hideColumn({
title: 'Actors', title: 'Actors',
}); });

3
tests/playwright/tests/db/columns/columnRelationalExtendedTests.spec.ts

@ -63,8 +63,8 @@ test.describe('Relational Columns', () => {
///////////// Belongs to ///////////// Belongs to
// //
await dashboard.treeView.openTable({ title: 'City' }); await dashboard.treeView.openTable({ title: 'City' });
await dashboard.grid.toolbar.fields.toggle({ title: 'Country', isLocallySaved: false, checked: true });
const countryList = [['Spain'], ['Saudi Arabia']]; const countryList = [['Spain'], ['Saudi Arabia']];
for (let i = 0; i < countryList.length; i++) { for (let i = 0; i < countryList.length; i++) {
await dashboard.grid.cell.verifyVirtualCell({ await dashboard.grid.cell.verifyVirtualCell({
@ -79,6 +79,7 @@ test.describe('Relational Columns', () => {
///////////// Many to many ///////////// Many to many
// //
await dashboard.treeView.openTable({ title: 'Actor' }); await dashboard.treeView.openTable({ title: 'Actor' });
await dashboard.grid.toolbar.fields.toggle({ title: 'Films', isLocallySaved: false, checked: true });
const filmList = [ const filmList = [
[ [
'ACADEMY DINOSAUR', 'ACADEMY DINOSAUR',

33
tests/playwright/tests/db/features/metaLTAR.spec.ts

@ -111,6 +111,7 @@ test.describe.serial('Test table', () => {
parentId: tables[0].id, parentId: tables[0].id,
childId: tables[1].id, childId: tables[1].id,
type: 'hm', type: 'hm',
view_id: tables[0].views[0].id,
}); });
await api.dbTableColumn.create(tables[1].id, { await api.dbTableColumn.create(tables[1].id, {
uidt: UITypes.Links, uidt: UITypes.Links,
@ -119,6 +120,7 @@ test.describe.serial('Test table', () => {
parentId: tables[1].id, parentId: tables[1].id,
childId: tables[2].id, childId: tables[2].id,
type: 'hm', type: 'hm',
view_id: tables[1].views[0].id,
}); });
// TableA <mm> TableD <mm> TableE // TableA <mm> TableD <mm> TableE
@ -129,6 +131,7 @@ test.describe.serial('Test table', () => {
parentId: tables[0].id, parentId: tables[0].id,
childId: tables[3].id, childId: tables[3].id,
type: 'mm', type: 'mm',
view_id: tables[0].views[0].id,
}); });
await api.dbTableColumn.create(tables[3].id, { await api.dbTableColumn.create(tables[3].id, {
uidt: UITypes.Links, uidt: UITypes.Links,
@ -137,6 +140,7 @@ test.describe.serial('Test table', () => {
parentId: tables[3].id, parentId: tables[3].id,
childId: tables[4].id, childId: tables[4].id,
type: 'mm', type: 'mm',
view_id: tables[3].views[0].id,
}); });
// TableA <hm> TableA : self relation // TableA <hm> TableA : self relation
@ -147,6 +151,7 @@ test.describe.serial('Test table', () => {
parentId: tables[0].id, parentId: tables[0].id,
childId: tables[0].id, childId: tables[0].id,
type: 'hm', type: 'hm',
view_id: tables[0].views[0].id,
}); });
// TableA <mm> TableA : self relation // TableA <mm> TableA : self relation
@ -157,6 +162,7 @@ test.describe.serial('Test table', () => {
parentId: tables[0].id, parentId: tables[0].id,
childId: tables[0].id, childId: tables[0].id,
type: 'mm', type: 'mm',
view_id: tables[0].views[0].id,
}); });
// Add links // Add links
@ -212,6 +218,33 @@ test.describe.serial('Test table', () => {
// refresh page // refresh page
await page.reload(); await page.reload();
const hiddenLinksTableColumns = [
{
tableName: 'Table1',
columns: ['Table0'],
},
{
tableName: 'Table2',
columns: ['Table1'],
},
{
tableName: 'Table3',
columns: ['Table0s'],
},
{
tableName: 'Table4',
columns: ['Table3s'],
},
];
// Unhide links columns
for (const table of hiddenLinksTableColumns) {
await dashboard.treeView.openTable({ title: table.tableName });
for (const column of table.columns) {
await dashboard.grid.toolbar.fields.toggle({ title: column, isLocallySaved: false, checked: true });
}
}
}); });
test.afterEach(async () => { test.afterEach(async () => {

6
tests/playwright/tests/db/views/viewGridShare.spec.ts

@ -128,6 +128,9 @@ test.describe('Shared view', () => {
await dashboard.closeTab({ title: 'Team & Auth' }); await dashboard.closeTab({ title: 'Team & Auth' });
await dashboard.treeView.openTable({ title: 'Address' }); await dashboard.treeView.openTable({ title: 'Address' });
// Unhide City column
await dashboard.grid.toolbar.fields.toggle({ title: 'City', isLocallySaved: false, checked: true });
// hide column // hide column
await dashboard.grid.toolbar.fields.toggle({ title: 'Address2' }); await dashboard.grid.toolbar.fields.toggle({ title: 'Address2' });
await dashboard.grid.toolbar.fields.toggle({ title: 'Stores' }); await dashboard.grid.toolbar.fields.toggle({ title: 'Stores' });
@ -168,7 +171,6 @@ test.describe('Shared view', () => {
{ title: 'Address', isVisible: true }, { title: 'Address', isVisible: true },
{ title: 'Address2', isVisible: false }, { title: 'Address2', isVisible: false },
{ title: 'District', isVisible: true }, { title: 'District', isVisible: true },
{ title: 'City', isVisible: true },
{ title: 'PostalCode', isVisible: true }, { title: 'PostalCode', isVisible: true },
{ title: 'Phone', isVisible: true }, { title: 'Phone', isVisible: true },
{ title: 'LastUpdate', isVisible: true }, { title: 'LastUpdate', isVisible: true },
@ -225,7 +227,7 @@ test.describe('Shared view', () => {
await sharedPage.grid.toolbar.clickFilter(); await sharedPage.grid.toolbar.clickFilter();
} }
await sharedPage.grid.toolbar.fields.toggle({ title: 'LastUpdate', isLocallySaved: true }); await sharedPage.grid.toolbar.fields.toggle({ title: 'LastUpdate', isLocallySaved: true });
expectedColumns[6].isVisible = false; expectedColumns[5].isVisible = false;
// verify new sort & filter criteria // verify new sort & filter criteria
for (const column of expectedColumns) { for (const column of expectedColumns) {

Loading…
Cancel
Save