diff --git a/packages/nc-gui/components/cell/DatePicker.vue b/packages/nc-gui/components/cell/DatePicker.vue index 39d807774b..f137d7ef63 100644 --- a/packages/nc-gui/components/cell/DatePicker.vue +++ b/packages/nc-gui/components/cell/DatePicker.vue @@ -104,7 +104,7 @@ const placeholder = computed(() => { if (isEditColumn.value && (modelValue === '' || modelValue === null)) { return t('labels.optional') } else if (modelValue === null && showNull.value) { - return t('general.null') + return t('general.null').toUpperCase() } else if (isDateInvalid.value) { return t('msg.invalidDate') } else { diff --git a/packages/nc-gui/components/cell/DateTimePicker.vue b/packages/nc-gui/components/cell/DateTimePicker.vue index 321b42adae..381feff1bb 100644 --- a/packages/nc-gui/components/cell/DateTimePicker.vue +++ b/packages/nc-gui/components/cell/DateTimePicker.vue @@ -157,7 +157,7 @@ const placeholder = computed(() => { if (isEditColumn.value && (modelValue === '' || modelValue === null)) { return t('labels.optional') } else if (modelValue === null && showNull.value) { - return t('general.null') + return t('general.null').toUpperCase() } else if (isDateInvalid.value) { return t('msg.invalidDate') } else { diff --git a/packages/nc-gui/components/cell/Decimal.vue b/packages/nc-gui/components/cell/Decimal.vue index aad130039f..9e02452f04 100644 --- a/packages/nc-gui/components/cell/Decimal.vue +++ b/packages/nc-gui/components/cell/Decimal.vue @@ -112,7 +112,7 @@ watch(isExpandedFormOpen, () => { @selectstart.capture.stop @mousedown.stop /> - {{ $t('general.null') }} + {{ $t('general.null') }} {{ displayValue }} diff --git a/packages/nc-gui/components/cell/Duration.vue b/packages/nc-gui/components/cell/Duration.vue index b4bf77263c..cde8bdf2ee 100644 --- a/packages/nc-gui/components/cell/Duration.vue +++ b/packages/nc-gui/components/cell/Duration.vue @@ -111,7 +111,7 @@ const focus: VNodeRef = (el) => @mousedown.stop /> - {{ $t('general.null') }} + {{ $t('general.null') }} {{ localState }} diff --git a/packages/nc-gui/components/cell/MultiSelect.vue b/packages/nc-gui/components/cell/MultiSelect.vue index 08fe8192e9..0295a8ef6f 100644 --- a/packages/nc-gui/components/cell/MultiSelect.vue +++ b/packages/nc-gui/components/cell/MultiSelect.vue @@ -567,7 +567,7 @@ const onFocus = () => { } :deep(.ant-select-selector) { - @apply !px-0; + @apply !pl-0; } :deep(.ant-select-selection-search-input) { diff --git a/packages/nc-gui/components/cell/Percent.vue b/packages/nc-gui/components/cell/Percent.vue index 94acc9186a..3ae6d120fd 100644 --- a/packages/nc-gui/components/cell/Percent.vue +++ b/packages/nc-gui/components/cell/Percent.vue @@ -143,7 +143,7 @@ const onTabPress = (e: KeyboardEvent) => { @selectstart.capture.stop @mousedown.stop /> - {{ $t('general.null') }} + {{ $t('general.null') }}
{ :disabled="readOnly || !editAllowed" :show-search="!isMobileMode && isOpen && active" :show-arrow="hasEditRoles && !readOnly && active && (vModel === null || vModel === undefined)" - :dropdown-class-name="`nc-dropdown-single-select-cell ${isOpen && active ? 'active' : ''}`" + :dropdown-class-name="`nc-dropdown-single-select-cell !min-w-200px ${isOpen && active ? 'active' : ''}`" + :dropdown-match-select-width="true" @select="onSelect" @keydown="onKeydown($event)" @search="search" @@ -399,7 +400,12 @@ const onFocus = () => { } :deep(.ant-select-selector) { - @apply !px-0; + @apply !pl-0 !pr-4; +} + +:deep(.ant-select-selector .ant-select-selection-item) { + @apply flex items-center; + text-overflow: clip; } :deep(.ant-select-selection-search-input) { diff --git a/packages/nc-gui/components/cell/TimePicker.vue b/packages/nc-gui/components/cell/TimePicker.vue index e61297f53f..3757f4a131 100644 --- a/packages/nc-gui/components/cell/TimePicker.vue +++ b/packages/nc-gui/components/cell/TimePicker.vue @@ -96,7 +96,7 @@ const placeholder = computed(() => { if (isEditColumn.value && (modelValue === '' || modelValue === null)) { return t('labels.optional') } else if (modelValue === null && showNull.value) { - return t('general.null') + return t('general.null').toUpperCase() } else if (isTimeInvalid.value) { return t('msg.invalidTime') } else { diff --git a/packages/nc-gui/components/cell/Url.vue b/packages/nc-gui/components/cell/Url.vue index b624417e93..8aa39bac32 100644 --- a/packages/nc-gui/components/cell/Url.vue +++ b/packages/nc-gui/components/cell/Url.vue @@ -108,7 +108,7 @@ watch( @mousedown.stop /> - $t('general.null') + {{ $t('general.null') }} { }" > @@ -310,7 +324,7 @@ const filterOption = (input: string, option: any) => { :open="isOpen && editAllowed" :disabled="readOnly || !editAllowed" :class="{ 'caret-transparent': !hasEditRoles }" - :dropdown-class-name="`nc-dropdown-user-select-cell ${isOpen ? 'active' : ''}`" + :dropdown-class-name="`nc-dropdown-user-select-cell !min-w-200px ${isOpen ? 'active' : ''}`" :filter-option="filterOption" @search="search" @keydown.stop @@ -326,7 +340,7 @@ const filterOption = (input: string, option: any) => { :class="`nc-select-option-${column.title}-${op.email}`" @click.stop > - + - - {{ op.display_name?.length ? op.display_name : op.email }} - + + + + {{ op.display_name?.length ? op.display_name : op.email }} + + @@ -437,7 +463,7 @@ const filterOption = (input: string, option: any) => { } :deep(.ant-select-selector) { - @apply !px-0; + @apply !pl-0; } :deep(.ant-select-selection-search-input) { diff --git a/packages/nc-gui/components/cell/YearPicker.vue b/packages/nc-gui/components/cell/YearPicker.vue index 69e3302912..3b7ab61455 100644 --- a/packages/nc-gui/components/cell/YearPicker.vue +++ b/packages/nc-gui/components/cell/YearPicker.vue @@ -83,7 +83,7 @@ const placeholder = computed(() => { if (isEditColumn.value && (modelValue === '' || modelValue === null)) { return t('labels.optional') } else if (modelValue === null && showNull.value) { - return t('general.null') + return t('general.null').toUpperCase() } else if (isYearInvalid.value) { return t('msg.invalidTime') } else { diff --git a/tests/playwright/pages/Dashboard/Grid/Column/UserOptionColumn.ts b/tests/playwright/pages/Dashboard/Grid/Column/UserOptionColumn.ts index c58d661a85..a123823f3e 100644 --- a/tests/playwright/pages/Dashboard/Grid/Column/UserOptionColumn.ts +++ b/tests/playwright/pages/Dashboard/Grid/Column/UserOptionColumn.ts @@ -51,6 +51,8 @@ export class UserOptionColumnPageObject extends BasePage { const selector = this.column.get().locator('.nc-user-select >> .ant-select-selector'); await selector.click(); + await this.rootPage.locator('.nc-dropdown-user-select-cell').waitFor({ state: 'visible' }); + if (multiSelect) { const optionsToSelect = Array.isArray(option) ? option : [option]; @@ -60,11 +62,12 @@ export class UserOptionColumnPageObject extends BasePage { // Press `Escape` to close the dropdown await this.rootPage.keyboard.press('Escape'); - await this.rootPage.locator('.nc-dropdown-user-select-cell').waitFor({ state: 'hidden' }); } else if (!Array.isArray(option)) { await this.selectOption({ option }); } + await this.rootPage.locator('.nc-dropdown-user-select-cell').waitFor({ state: 'hidden' }); + await this.column.save({ isUpdated: true }); } @@ -91,6 +94,8 @@ export class UserOptionColumnPageObject extends BasePage { await this.column.get().locator('.nc-cell-user > .nc-user-select').click(); + await this.rootPage.locator('.nc-dropdown-user-select-cell').waitFor({ state: 'visible' }); + expect(await this.rootPage.getByTestId(`select-option-${columnTitle}-undefined`).count()).toEqual(totalCount); await this.column.get().locator('.nc-cell-user').click(); diff --git a/tests/playwright/pages/Dashboard/Grid/Group.ts b/tests/playwright/pages/Dashboard/Grid/Group.ts index 8fe3e0c6ba..fba9a740e0 100644 --- a/tests/playwright/pages/Dashboard/Grid/Group.ts +++ b/tests/playwright/pages/Dashboard/Grid/Group.ts @@ -74,6 +74,7 @@ export class GroupPageObject extends BasePage { value: string; }) { const gridWrapper = this.get({ indexMap }); + await gridWrapper.scrollIntoViewIfNeeded(); await gridWrapper .locator(`.nc-group-table .nc-grid-row:nth-child(${rowIndex + 1}) [data-title="${columnHeader}"]`) .scrollIntoViewIfNeeded(); @@ -109,6 +110,14 @@ export class GroupPageObject extends BasePage { await this.get({ indexMap }).locator('.nc-grid-add-new-row').click(); const rowCount = index + 1; + + const isRowSaving = this.get({ indexMap }).getByTestId(`row-save-spinner-${rowCount}`); + // if required field is present then isRowSaving will be hidden (not present in DOM) + await isRowSaving?.waitFor({ state: 'hidden' }); + + // fallback + await this.rootPage.waitForTimeout(400); + await expect(this.get({ indexMap }).locator('.nc-grid-row')).toHaveCount(rowCount); await this._fillRow({ indexMap, index, columnHeader, value: rowValue }); diff --git a/tests/playwright/pages/Dashboard/Grid/index.ts b/tests/playwright/pages/Dashboard/Grid/index.ts index 019b0d7f87..35e00af4f2 100644 --- a/tests/playwright/pages/Dashboard/Grid/index.ts +++ b/tests/playwright/pages/Dashboard/Grid/index.ts @@ -123,10 +123,15 @@ export class GridPage extends BasePage { await this.get().locator('.nc-grid-add-new-cell').click(); - // wait for insert row response + const rowCount = index + 1; + + const isRowSaving = this.rootPage.getByTestId(`row-save-spinner-${rowCount}`); + // if required field is present then isRowSaving will be hidden (not present in DOM) + await isRowSaving?.waitFor({ state: 'hidden' }); + + // fallback await this.rootPage.waitForTimeout(400); - const rowCount = index + 1; await expect(this.get().locator('.nc-grid-row')).toHaveCount(rowCount); await this._fillRow({ index, columnHeader, value: rowValue }); diff --git a/tests/playwright/pages/Dashboard/common/Cell/SelectOptionCell.ts b/tests/playwright/pages/Dashboard/common/Cell/SelectOptionCell.ts index d8f6a2e6c7..44d1ee7ba6 100644 --- a/tests/playwright/pages/Dashboard/common/Cell/SelectOptionCell.ts +++ b/tests/playwright/pages/Dashboard/common/Cell/SelectOptionCell.ts @@ -39,22 +39,29 @@ export class SelectOptionCellPageObject extends BasePage { await selectCell.click(); + if (multiSelect) { + await this.rootPage.locator('.nc-dropdown-multi-select-cell').waitFor({ state: 'visible' }); + } else { + await this.rootPage.locator('.nc-dropdown-single-select-cell').waitFor({ state: 'visible' }); + } + if (index === -1) { const selectOption = this.rootPage.getByTestId(`select-option-${columnHeader}-undefined`).getByText(option); - await selectOption.waitFor({ state: 'visible' }); + await selectOption.scrollIntoViewIfNeeded(); await selectOption.click(); } else { const selectOption = this.rootPage.getByTestId(`select-option-${columnHeader}-${index}`).getByText(option); - await selectOption.waitFor({ state: 'visible' }); + await selectOption.scrollIntoViewIfNeeded(); await selectOption.click(); } - if (multiSelect) await this.get({ index, columnHeader }).click(); - - await this.rootPage - .getByTestId(`select-option-${columnHeader}-${index}`) - .getByText(option) - .waitFor({ state: 'hidden' }); + if (multiSelect) { + // Press `Escape` to close the dropdown + await this.rootPage.keyboard.press('Escape'); + await this.rootPage.locator('.nc-dropdown-multi-select-cell').waitFor({ state: 'hidden' }); + } else { + await this.rootPage.locator('.nc-dropdown-single-select-cell').waitFor({ state: 'hidden' }); + } } async clear({ index, columnHeader, multiSelect }: { index: number; columnHeader: string; multiSelect?: boolean }) { diff --git a/tests/playwright/pages/Dashboard/common/Cell/UserOptionCell.ts b/tests/playwright/pages/Dashboard/common/Cell/UserOptionCell.ts index 8b6398f5c6..56e84ab968 100644 --- a/tests/playwright/pages/Dashboard/common/Cell/UserOptionCell.ts +++ b/tests/playwright/pages/Dashboard/common/Cell/UserOptionCell.ts @@ -37,22 +37,24 @@ export class UserOptionCellPageObject extends BasePage { await selectCell.click(); + await this.rootPage.locator('.nc-dropdown-user-select-cell').waitFor({ state: 'visible' }); + if (index === -1) { const selectOption = this.rootPage.getByTestId(`select-option-${columnHeader}-undefined`).getByText(option); - await selectOption.waitFor({ state: 'visible' }); + await selectOption.scrollIntoViewIfNeeded(); await selectOption.click(); } else { const selectOption = this.rootPage.getByTestId(`select-option-${columnHeader}-${index}`).getByText(option); - await selectOption.waitFor({ state: 'visible' }); + await selectOption.scrollIntoViewIfNeeded(); await selectOption.click(); } - if (multiSelect) await this.get({ index, columnHeader }).click(); + if (multiSelect) { + // Press `Escape` to close the dropdown + await this.rootPage.keyboard.press('Escape'); + } - await this.rootPage - .getByTestId(`select-option-${columnHeader}-${index}`) - .getByText(option) - .waitFor({ state: 'hidden' }); + await this.rootPage.locator('.nc-dropdown-user-select-cell').waitFor({ state: 'hidden' }); } async clear({ index, columnHeader, multiSelect }: { index: number; columnHeader: string; multiSelect?: boolean }) { diff --git a/tests/playwright/tests/db/views/viewForm.spec.ts b/tests/playwright/tests/db/views/viewForm.spec.ts index 747613db70..82fc2db602 100644 --- a/tests/playwright/tests/db/views/viewForm.spec.ts +++ b/tests/playwright/tests/db/views/viewForm.spec.ts @@ -478,6 +478,7 @@ test.describe('Form view', () => { columnHeader: 'SingleSelect', option: 'jan', multiSelect: false, + ignoreDblClick: true, }); // Click on multi select options