Skip to content

Commit 94255b6

Browse files
authored
Merge pull request #2456 from nextcloud/feat/noid/row-actions
πŸ“šβŒ Add copy/delete row actions
2 parents 98a7df1 + bf11f2c commit 94255b6

29 files changed

Lines changed: 277 additions & 97 deletions

β€Žcypress/component/ContentReferenceWidget.cy.jsβ€Ž

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -80,8 +80,9 @@ describe('ContentReferenceWidget', () => {
8080
cy.reply('**/index.php/apps/tables/row/*', rowData)
8181
})
8282

83-
// Click the edit button on the first row
84-
cy.get('@rows').first().find('td.sticky button').click({ force: true })
83+
// Open the row action menu on the first row, then click Edit
84+
cy.get('@rows').first().find('[data-cy="rowActionMenu"] button').click({ force: true })
85+
cy.get('[data-cy="editRowBtn"]').click()
8586

8687
// Get the first field of the Edit Row modal
8788
cy.get('.modal__content').as('editRowModal')

β€Žcypress/e2e/helpers/viewFilteringSelectionSetup.jsβ€Ž

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ const addRow = (title, selection, multiSelection, checked) => {
8181

8282
cy.get('[data-cy="createRowSaveButton"]').click()
8383
cy.get('[data-cy="createRowModal"]').should('not.exist')
84-
cy.get('.toastify.toast-success').should('be.visible')
85-
cy.get('.toastify.toast-success .toast-close').click({ multiple: true })
84+
cy.get('body').then($body => {
85+
$body.find('.toastify.toast-success .toast-close').each((_, el) => el.click())
86+
})
8687
}

β€Žcypress/e2e/view-filtering-selection-row-removal.cy.jsβ€Ž

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,16 +22,19 @@ describe('Filtering view with row removal', () => {
2222

2323
it('Removes rows from the filtered view once they no longer match', () => {
2424
cy.intercept({ method: 'PUT', url: '**/apps/tables/row/*' }).as('updateCheckedRow')
25-
cy.contains('[data-cy="ncTable"] [data-cy="customTableRow"]', 'first row').closest('[data-cy="customTableRow"]').find('[data-cy="editRowBtn"]').click()
25+
cy.contains('[data-cy="ncTable"] [data-cy="customTableRow"]', 'first row').closest('[data-cy="customTableRow"]').find('[data-cy="rowActionMenu"] button').click()
26+
cy.get('[data-cy="editRowBtn"]').click()
2627
cy.get('[data-cy="editRowModal"] .checkbox-radio-switch').click()
2728
cy.get('[data-cy="editRowSaveButton"]').click()
2829
cy.wait('@updateCheckedRow')
29-
cy.contains('[data-cy="ncTable"] [data-cy="customTableRow"]', 'first row').should('not.exist')
30+
// Wait for the row to be removed from the filtered view (async removal)
31+
cy.contains('[data-cy="ncTable"] [data-cy="customTableRow"]', 'first row', { timeout: 8000 }).should('not.exist')
3032
cy.get('[data-cy="editRowModal"]').should('not.exist')
3133

3234
cy.intercept({ method: 'PUT', url: '**/apps/tables/row/*' }).as('inlineUpdateRow')
3335
cy.contains('[data-cy="ncTable"] [data-cy="customTableRow"]', 'second row').closest('[data-cy="customTableRow"]').find('.inline-editing-container input').click({ force: true })
3436
cy.wait('@inlineUpdateRow')
35-
cy.contains('[data-cy="ncTable"] [data-cy="customTableRow"]', 'second row').should('not.exist')
37+
// Wait for the row to be removed from the filtered view (async removal)
38+
cy.contains('[data-cy="ncTable"] [data-cy="customTableRow"]', 'second row', { timeout: 8000 }).should('not.exist')
3639
})
3740
})

β€Žlib/Service/RowService.phpβ€Ž

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,7 @@ public function create(?int $tableId, ?int $viewId, RowDataInput|array $data, ?s
182182
if ($userId) {
183183
$this->userId = $userId;
184184
}
185-
if ($this->userId === null || $this->userId === '') {
185+
if ($this->userId === null || ($this->userId === '' && !$this->isPublicContext)) {
186186
$e = new \Exception('No user id in context, but needed.');
187187
$this->logger->error($e->getMessage(), ['exception' => $e]);
188188
throw new InternalError(get_class($this) . ' - ' . __FUNCTION__ . ': ' . $e->getMessage());
@@ -571,7 +571,7 @@ public function updateSet(
571571
if ($userId) {
572572
$this->userId = $userId;
573573
}
574-
if ($this->userId === null || $this->userId === '') {
574+
if ($this->userId === null || ($this->userId === '' && !$this->isPublicContext)) {
575575
$e = new \Exception('No user id in context, but needed.');
576576
$this->logger->error($e->getMessage(), ['exception' => $e]);
577577
throw new InternalError(get_class($this) . ' - ' . __FUNCTION__ . ': ' . $e->getMessage());

β€Žlib/Service/SuperService.phpβ€Ž

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ class SuperService {
1616

1717
protected ?string $userId;
1818

19+
protected bool $isPublicContext = false;
20+
1921
public function __construct(LoggerInterface $logger, ?string $userId, PermissionsService $permissionsService) {
2022
$this->permissionsService = $permissionsService;
2123
$this->logger = $logger;
@@ -24,6 +26,7 @@ public function __construct(LoggerInterface $logger, ?string $userId, Permission
2426

2527
public function setPublicContext(): void {
2628
$this->userId = '';
29+
$this->isPublicContext = true;
2730
$this->permissionsService->setPublicContext();
2831
}
2932
}

β€Žplaywright/e2e/column-datetime.spec.tsβ€Ž

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
*/
55

66
import { test, expect } from '../support/fixtures'
7-
import { createDatetimeColumn, createTable, loadTable, removeColumn } from '../support/commands'
7+
import { createDatetimeColumn, createTable, loadTable, openRowActionMenu, removeColumn } from '../support/commands'
88

99
const columnTitle = 'date and time'
1010
const tableTitle = 'Test datetime'
@@ -32,9 +32,10 @@ test.describe('Test column ' + columnTitle, () => {
3232
await expect(page.locator('.custom-table table tr td div').filter({ hasText: '5:15' }).first()).toBeVisible()
3333

3434
// delete row
35-
await page.locator('.NcTable tr td button').first().click()
36-
await page.locator('button').filter({ hasText: 'Delete' }).click()
37-
await page.locator('button').filter({ hasText: /I really/ }).click({ force: true })
35+
await openRowActionMenu(page, page.locator('[data-cy="customTableRow"]').first())
36+
await page.locator('[data-cy="deleteRowBtn"]').click()
37+
await page.locator('[data-cy="confirmDialog"]').getByRole('button', { name: 'Confirm' }).click()
38+
await expect(page.locator('[data-cy="customTableRow"]')).toHaveCount(0, { timeout: 10000 })
3839

3940
await removeColumn(page, columnTitle)
4041
})

β€Žplaywright/e2e/column-datetimeDate.spec.tsβ€Ž

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
*/
55

66
import { test, expect } from '../support/fixtures'
7-
import { createDatetimeDateColumn, createTable, loadTable, removeColumn } from '../support/commands'
7+
import { createDatetimeDateColumn, createTable, loadTable, openRowActionMenu, removeColumn } from '../support/commands'
88

99
const columnTitle = 'date'
1010
const tableTitle = 'Test datetimeDate'
@@ -29,9 +29,10 @@ test.describe('Test column ' + columnTitle, () => {
2929
await expect(page.locator('.custom-table table tr td div').filter({ hasText: '2023' }).first()).toBeVisible()
3030

3131
// delete row
32-
await page.locator('.NcTable tr td button').first().click()
33-
await page.locator('button').filter({ hasText: 'Delete' }).click()
34-
await page.locator('button').filter({ hasText: /I really/ }).click({ force: true })
32+
await openRowActionMenu(page, page.locator('[data-cy="customTableRow"]').first())
33+
await page.locator('[data-cy="deleteRowBtn"]').click()
34+
await page.locator('[data-cy="confirmDialog"]').getByRole('button', { name: 'Confirm' }).click()
35+
await expect(page.locator('[data-cy="customTableRow"]')).toHaveCount(0, { timeout: 10000 })
3536

3637
await removeColumn(page, columnTitle)
3738
})

β€Žplaywright/e2e/column-datetimeTime.spec.tsβ€Ž

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
*/
55

66
import { test, expect } from '../support/fixtures'
7-
import { createDatetimeTimeColumn, createTable, loadTable, removeColumn } from '../support/commands'
7+
import { createDatetimeTimeColumn, createTable, loadTable, openRowActionMenu, removeColumn } from '../support/commands'
88

99
const columnTitle = 'time'
1010
const tableTitle = 'Test datetimeTime'
@@ -27,9 +27,10 @@ test.describe('Test column ' + columnTitle, () => {
2727
await expect(page.locator('.custom-table table tr td div').filter({ hasText: '5:15' }).first()).toBeVisible()
2828

2929
// delete row
30-
await page.locator('.NcTable tr td button').first().click()
31-
await page.locator('button').filter({ hasText: 'Delete' }).click()
32-
await page.locator('button').filter({ hasText: /I really/ }).click({ force: true })
30+
await openRowActionMenu(page, page.locator('[data-cy="customTableRow"]').first())
31+
await page.locator('[data-cy="deleteRowBtn"]').click()
32+
await page.locator('[data-cy="confirmDialog"]').getByRole('button', { name: 'Confirm' }).click()
33+
await expect(page.locator('[data-cy="customTableRow"]')).toHaveCount(0, { timeout: 10000 })
3334

3435
await removeColumn(page, columnTitle)
3536
})

β€Žplaywright/e2e/column-number.spec.tsβ€Ž

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
*/
55

66
import { test, expect } from '../support/fixtures'
7-
import { createNumberColumn, createTable, loadTable, removeColumn } from '../support/commands'
7+
import { createNumberColumn, createTable, loadTable, openRowActionMenu, removeColumn } from '../support/commands'
88

99
const columnTitle = 'num1'
1010
const tableTitle = 'Test number column'
@@ -26,9 +26,10 @@ test.describe('Test column number', () => {
2626
await expect(page.locator('.custom-table table tr td div').filter({ hasText: '21.00' }).first()).toBeVisible()
2727

2828
// delete row
29-
await page.locator('.NcTable tr td button').first().click()
30-
await page.locator('button').filter({ hasText: 'Delete' }).click()
31-
await page.locator('button').filter({ hasText: /I really/ }).click({ force: true })
29+
await openRowActionMenu(page, page.locator('[data-cy="customTableRow"]').first())
30+
await page.locator('[data-cy="deleteRowBtn"]').click()
31+
await page.locator('[data-cy="confirmDialog"]').getByRole('button', { name: 'Confirm' }).click()
32+
await expect(page.locator('[data-cy="customTableRow"]')).toHaveCount(0, { timeout: 10000 })
3233

3334
// insert row with float value
3435
await page.locator('button').filter({ hasText: 'Create row' }).click()
@@ -38,9 +39,10 @@ test.describe('Test column number', () => {
3839
await expect(page.locator('.custom-table table tr td div').filter({ hasText: '21.30' }).first()).toBeVisible()
3940

4041
// delete row
41-
await page.locator('.NcTable tr td button').first().click()
42-
await page.locator('button').filter({ hasText: 'Delete' }).click()
43-
await page.locator('button').filter({ hasText: /I really/ }).click({ force: true })
42+
await openRowActionMenu(page, page.locator('[data-cy="customTableRow"]').first())
43+
await page.locator('[data-cy="deleteRowBtn"]').click()
44+
await page.locator('[data-cy="confirmDialog"]').getByRole('button', { name: 'Confirm' }).click()
45+
await expect(page.locator('[data-cy="customTableRow"]')).toHaveCount(0, { timeout: 10000 })
4446

4547
await removeColumn(page, columnTitle)
4648
})

β€Žplaywright/e2e/column-selection-multi.spec.tsβ€Ž

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
*/
55

66
import { test, expect } from '../support/fixtures'
7-
import { createSelectionMultiColumn, createTable, loadTable, removeColumn } from '../support/commands'
7+
import { createSelectionMultiColumn, createTable, loadTable, openRowActionMenu, removeColumn } from '../support/commands'
88

99
const columnTitle = 'multi selection'
1010
const tableTitle = 'Test number column'
@@ -42,15 +42,17 @@ test.describe('Test column ' + columnTitle, () => {
4242
await expect(page.locator('.custom-table table tr td .cell-multi-selection').filter({ hasText: 'third option' }).first()).toBeVisible()
4343

4444
// delete first row
45-
await page.locator('.NcTable tr td button').first().click()
46-
await page.locator('button').filter({ hasText: 'Delete' }).click()
47-
await page.locator('button').filter({ hasText: /I really/ }).click({ force: true })
45+
await openRowActionMenu(page, page.locator('[data-cy="customTableRow"]').first())
46+
await page.locator('[data-cy="deleteRowBtn"]').click()
47+
await page.locator('[data-cy="confirmDialog"]').getByRole('button', { name: 'Confirm' }).click()
48+
await expect(page.locator('[data-cy="customTableRow"]')).toHaveCount(1, { timeout: 10000 })
4849

4950
await expect(page.locator('.custom-table table tr td .cell-multi-selection', { hasText: 'first option' })).toBeHidden()
5051
await expect(page.locator('.custom-table table tr td .cell-multi-selection', { hasText: 'second option' })).toBeHidden()
5152

5253
// edit second row (which is now first row)
53-
await page.locator('.NcTable tr td button').first().click()
54+
await openRowActionMenu(page, page.locator('[data-cy="customTableRow"]').first())
55+
await page.locator('[data-cy="editRowBtn"]').click()
5456
await page.locator('.modal__content .slot input').first().click()
5557
await page.locator('ul.vs__dropdown-menu li span[title="first option"]').first().click()
5658
await page.locator('.modal__content .title').first().click()
@@ -60,9 +62,10 @@ test.describe('Test column ' + columnTitle, () => {
6062
await expect(page.locator('.custom-table table tr td .cell-multi-selection').filter({ hasText: 'third option' }).first()).toBeVisible()
6163

6264
// delete first row
63-
await page.locator('.NcTable tr td button').first().click()
64-
await page.locator('button').filter({ hasText: 'Delete' }).click()
65-
await page.locator('button').filter({ hasText: /I really/ }).click({ force: true })
65+
await openRowActionMenu(page, page.locator('[data-cy="customTableRow"]').first())
66+
await page.locator('[data-cy="deleteRowBtn"]').click()
67+
await page.locator('[data-cy="confirmDialog"]').getByRole('button', { name: 'Confirm' }).click()
68+
await expect(page.locator('[data-cy="customTableRow"]')).toHaveCount(0, { timeout: 10000 })
6669

6770
await removeColumn(page, columnTitle)
6871
})
@@ -79,6 +82,6 @@ test.describe('Test column ' + columnTitle, () => {
7982
await page.locator('button').filter({ hasText: 'Save' }).click()
8083

8184
await expect(page.locator('.custom-table table tr td .cell-multi-selection').first()).toBeVisible()
82-
await expect(page.locator('.NcTable tr td button').first()).toBeVisible()
85+
await expect(page.locator('[data-cy="customTableRow"]').first()).toBeVisible()
8386
})
8487
})

0 commit comments

Comments
Β (0)