Skip to content

Commit 8105ddd

Browse files
committed
Enhancement: Make tables import asynchronous (code review fixes wip)
Signed-off-by: Kostiantyn Miakshyn <molodchick@gmail.com>
1 parent 1fb02a8 commit 8105ddd

12 files changed

Lines changed: 1493 additions & 82 deletions

File tree

REUSE.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ SPDX-FileCopyrightText = "2017 Nextcloud GmbH and Nextcloud contributors"
6666
SPDX-License-Identifier = "AGPL-3.0-or-later"
6767

6868
[[annotations]]
69-
path = ["cypress/styleguide/assets/img/filetypes/font.svg", "cypress/styleguide/assets/img/actions/star-rounded.svg", "cypress/fixtures/example.json", "cypress/fixtures/NC_server_test.pdf", "cypress/fixtures/photo-test-1.jpeg", "cypress/fixtures/test-import.csv", "docs/permissions-matrix.xlsx", "tests/stub.phpstub", "tests/integration/composer.json", "tests/integration/composer.lock", "tests/integration/base-query-count.txt"]
69+
path = ["cypress/styleguide/assets/img/filetypes/font.svg", "cypress/styleguide/assets/img/actions/star-rounded.svg", "cypress/fixtures/example.json", "cypress/fixtures/NC_server_test.pdf", "cypress/fixtures/photo-test-1.jpeg", "cypress/fixtures/test-import-large.csv", "cypress/fixtures/test-import-small.csv", "docs/permissions-matrix.xlsx", "tests/stub.phpstub", "tests/integration/composer.json", "tests/integration/composer.lock", "tests/integration/base-query-count.txt"]
7070
precedence = "aggregate"
7171
SPDX-FileCopyrightText = "2023 Nextcloud GmbH and Nextcloud contributors"
7272
SPDX-License-Identifier = "AGPL-3.0-or-later"

appinfo/routes.php

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -102,13 +102,13 @@
102102

103103
// import
104104
['name' => 'import#previewImportTable', 'url' => '/import-preview/table/{tableId}', 'verb' => 'POST'],
105-
['name' => 'import#scheduleImportInTable', 'url' => '/import/table/{tableId}/jobs', 'verb' => 'POST'],
106-
['name' => 'import#scheduleImportInView', 'url' => '/import/view/{viewId}/jobs', 'verb' => 'POST'],
105+
['name' => 'import#importV2InTable', 'url' => '/v2/import/table/{tableId}', 'verb' => 'POST'],
106+
['name' => 'import#importV2InView', 'url' => '/v2/import/view/{viewId}', 'verb' => 'POST'],
107107
['name' => 'import#previewImportView', 'url' => '/import-preview/view/{viewId}', 'verb' => 'POST'],
108108
['name' => 'import#previewUploadImportTable', 'url' => '/importupload-preview/table/{tableId}', 'verb' => 'POST'],
109-
['name' => 'import#scheduleImportUploadInTable', 'url' => '/importupload/table/{tableId}/jobs', 'verb' => 'POST'],
110109
['name' => 'import#previewUploadImportView', 'url' => '/importupload-preview/view/{viewId}', 'verb' => 'POST'],
111-
['name' => 'import#scheduleImportUploadInView', 'url' => '/importupload/view/{viewId}/jobs', 'verb' => 'POST'],
110+
['name' => 'import#importV2UploadInTable', 'url' => '/v2/importupload/table/{tableId}', 'verb' => 'POST'],
111+
['name' => 'import#importV2UploadInView', 'url' => '/v2/importupload/view/{viewId}', 'verb' => 'POST'],
112112
// deprecated endpoints
113113
['name' => 'import#importUploadInTable', 'url' => '/importupload/table/{tableId}', 'verb' => 'POST'],
114114
['name' => 'import#importUploadInView', 'url' => '/importupload/view/{viewId}', 'verb' => 'POST'],

cypress/e2e/tables-import.cy.js

Lines changed: 94 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@ describe('Import csv', () => {
1010
cy.createRandomUser().then(user => {
1111
localUser = user
1212
cy.login(localUser)
13-
cy.uploadFile('test-import.csv', 'text/csv')
13+
cy.uploadFile('test-import-small.csv', 'text/csv')
14+
cy.uploadFile('test-import-large.csv', 'text/csv')
1415
})
1516
})
1617

@@ -19,32 +20,74 @@ describe('Import csv', () => {
1920
cy.visit('apps/tables')
2021
})
2122

22-
it('Import csv from Files', () => {
23+
it('Import small csv from Files', () => {
2324
cy.loadTable('Welcome to Nextcloud Tables!')
2425
cy.clickOnTableThreeDotMenu('Import')
2526
cy.get('.modal__content button').contains('Select from Files').click()
26-
cy.get('.file-picker__files').contains('test-import').click()
27+
cy.get('.file-picker__files').contains('test-import-small').click()
2728
cy.get('.file-picker button span').contains('Import').click()
2829
cy.get('.modal__content .import-filename', { timeout: 5000 }).should('be.visible')
2930

3031
cy.get('.modal__content button').contains('Preview').click()
3132
cy.get('.file_import__preview tbody tr').should('have.length', 4)
3233

33-
cy.intercept({ method: 'POST', url: '**/apps/tables/import/table/*/jobs' }).as('importUploadReq')
34+
cy.intercept({ method: 'POST', url: '**/apps/tables/import/table/*'}).as('importUploadReq')
35+
cy.get('.modal__content button').contains('Import').click()
36+
cy.wait('@importUploadReq')
37+
cy.get('[data-cy="importResultColumnsFound"]').should('contain.text', '4')
38+
cy.get('[data-cy="importResultColumnsMatch"]').should('contain.text', '4')
39+
cy.get('[data-cy="importResultColumnsCreated"]').should('contain.text', '0')
40+
cy.get('[data-cy="importResultRowsInserted"]').should('contain.text', '3')
41+
cy.get('[data-cy="importResultParsingErrors"]').should('contain.text', '0')
42+
cy.get('[data-cy="importResultRowErrors"]').should('contain.text', '0')
43+
})
44+
45+
it('Import large csv from Files', () => {
46+
cy.loadTable('Welcome to Nextcloud Tables!')
47+
cy.clickOnTableThreeDotMenu('Import')
48+
cy.get('.modal__content button').contains('Select from Files').click()
49+
cy.get('.file-picker__files').contains('test-import-large').click()
50+
cy.get('.file-picker button span').contains('Import').click()
51+
cy.get('.modal__content .import-filename', { timeout: 5000 }).should('be.visible')
52+
53+
cy.get('.modal__content button').contains('Preview').click()
54+
cy.get('.file_import__preview tbody tr').should('have.length', 4)
55+
56+
cy.intercept({ method: 'POST', url: '**/apps/tables/import/table/*' }).as('importUploadReq')
3457
cy.get('.modal__content button').contains('Import').click()
3558
cy.wait('@importUploadReq').its('response.statusCode').should('equal', 200)
3659
})
3760

38-
it('Import csv from device', () => {
61+
it('Import small csv from device', () => {
3962
cy.loadTable('Welcome to Nextcloud Tables!')
4063
cy.clickOnTableThreeDotMenu('Import')
4164
cy.get('.modal__content button').contains('Upload from device').click()
42-
cy.get('input[type="file"]').selectFile('cypress/fixtures/test-import.csv', { force: true })
65+
cy.get('input[type="file"]').selectFile('cypress/fixtures/test-import-small.csv', { force: true })
4366

4467
cy.get('.modal__content button').contains('Preview').click()
4568
cy.get('.file_import__preview tbody tr', { timeout: 20000 }).should('have.length', 4)
4669

47-
cy.intercept({ method: 'POST', url: '**/apps/tables/importupload/table/*/jobs' }).as('importUploadReq')
70+
cy.intercept({ method: 'POST', url: '**/apps/tables/importupload/table/*'}).as('importUploadReq')
71+
cy.get('.modal__content button').contains('Import').click()
72+
cy.wait('@importUploadReq')
73+
cy.get('[data-cy="importResultColumnsFound"]', { timeout: 20000 }).should('contain.text', '4')
74+
cy.get('[data-cy="importResultColumnsMatch"]').should('contain.text', '4')
75+
cy.get('[data-cy="importResultColumnsCreated"]').should('contain.text', '0')
76+
cy.get('[data-cy="importResultRowsInserted"]').should('contain.text', '3')
77+
cy.get('[data-cy="importResultParsingErrors"]').should('contain.text', '0')
78+
cy.get('[data-cy="importResultRowErrors"]').should('contain.text', '0')
79+
})
80+
81+
it('Import large csv from device', () => {
82+
cy.loadTable('Welcome to Nextcloud Tables!')
83+
cy.clickOnTableThreeDotMenu('Import')
84+
cy.get('.modal__content button').contains('Upload from device').click()
85+
cy.get('input[type="file"]').selectFile('cypress/fixtures/test-import-large.csv', { force: true })
86+
87+
cy.get('.modal__content button').contains('Preview').click()
88+
cy.get('.file_import__preview tbody tr', { timeout: 20000 }).should('have.length', 4)
89+
90+
cy.intercept({ method: 'POST', url: '**/apps/tables/importupload/table/*' }).as('importUploadReq')
4891
cy.get('.modal__content button').contains('Import').click()
4992
cy.wait('@importUploadReq').its('response.statusCode').should('equal', 200)
5093
})
@@ -71,9 +114,16 @@ describe('Import csv', () => {
71114
cy.get('.modal__content button').contains('Preview').click()
72115
cy.get('.file_import__preview tbody tr', { timeout: 20000 }).should('have.length', 3)
73116

74-
cy.intercept({ method: 'POST', url: '**/apps/tables/importupload/table/*/jobs' }).as('importUploadReq')
117+
cy.intercept({ method: 'POST', url: '**/apps/tables/importupload/table/*'}).as('importUploadReq')
75118
cy.get('.modal__content button').contains('Import').click()
76-
cy.wait('@importUploadReq').its('response.statusCode').should('equal', 200)
119+
cy.wait('@importUploadReq')
120+
cy.get('[data-cy="importResultColumnsFound"]', { timeout: 20000 }).should('contain.text', '2')
121+
cy.get('[data-cy="importResultColumnsMatch"]').should('contain.text', '3')
122+
cy.get('[data-cy="importResultColumnsCreated"]').should('contain.text', '0')
123+
cy.get('[data-cy="importResultRowsInserted"]').should('contain.text', '0')
124+
cy.get('[data-cy="importResultRowsUpdated"]').should('contain.text', '1')
125+
cy.get('[data-cy="importResultParsingErrors"]').should('contain.text', '0')
126+
cy.get('[data-cy="importResultRowErrors"]').should('contain.text', '0')
77127
})
78128

79129
})
@@ -84,7 +134,8 @@ describe('Import csv from Files file action', () => {
84134
cy.createRandomUser().then(user => {
85135
localUser = user
86136
cy.login(localUser)
87-
cy.uploadFile('test-import.csv', 'text/csv')
137+
cy.uploadFile('test-import-small.csv', 'text/csv')
138+
cy.uploadFile('test-import-large.csv', 'text/csv')
88139
})
89140
})
90141

@@ -93,20 +144,39 @@ describe('Import csv from Files file action', () => {
93144
cy.visit('apps/files/files')
94145
})
95146

96-
it('Import to new table', () => {
97-
cy.get('[data-cy-files-list-row-name="test-import.csv"] [data-cy-files-list-row-actions] .action-item button').click()
147+
it('Import small file to new table', () => {
148+
cy.get('[data-cy-files-list-row-name="test-import-small.csv"] [data-cy-files-list-row-actions] .action-item button').click()
98149
cy.get('[data-cy-files-list-row-action="import-to-tables"]').click()
99150

100151
cy.intercept({
101152
method: 'POST',
102-
url: '**/apps/tables/import/table/*/jobs',
153+
url: '**/apps/tables/import/table/*'
103154
}).as('importNewTableReq')
104155
cy.get('[data-cy="fileActionImportButton"]').click({ force: true })
105156
cy.wait('@importNewTableReq').its('response.statusCode').should('equal', 200)
157+
158+
cy.get('[data-cy="importResultColumnsFound"]').should('contain.text', '4')
159+
cy.get('[data-cy="importResultColumnsMatch"]').should('contain.text', '0')
160+
cy.get('[data-cy="importResultColumnsCreated"]').should('contain.text', '4')
161+
cy.get('[data-cy="importResultRowsInserted"]').should('contain.text', '3')
162+
cy.get('[data-cy="importResultParsingErrors"]').should('contain.text', '0')
163+
cy.get('[data-cy="importResultRowErrors"]').should('contain.text', '0')
106164
})
107165

108-
it('Import to existing table', () => {
109-
cy.get('[data-cy-files-list-row-name="test-import.csv"] [data-cy-files-list-row-actions] .action-item button').click()
166+
it('Import large file to new table', () => {
167+
cy.get('[data-cy-files-list-row-name="test-import-large.csv"] [data-cy-files-list-row-actions] .action-item button').click()
168+
cy.get('[data-cy-files-list-row-action="import-to-tables"]').click()
169+
170+
cy.intercept({
171+
method: 'POST',
172+
url: '**/apps/tables/import/table/*'
173+
}).as('importNewTableReq')
174+
cy.get('[data-cy="fileActionImportButton"]').click({ force: true })
175+
cy.wait('@importNewTableReq').its('response.statusCode').should('equal', 200)
176+
})
177+
178+
it('Import small file to existing table', () => {
179+
cy.get('[data-cy-files-list-row-name="test-import-small.csv"] [data-cy-files-list-row-actions] .action-item button').click()
110180
cy.get('[data-cy-files-list-row-action="import-to-tables"]').click()
111181

112182
cy.get('.modal__content [data-cy="importAsNewTableSwitch"] input').uncheck({ force: true })
@@ -115,10 +185,17 @@ describe('Import csv from Files file action', () => {
115185

116186
cy.intercept({
117187
method: 'POST',
118-
url: '**/apps/tables/import/table/*/jobs',
188+
url: '**/apps/tables/import/table/*'
119189
}).as('importExistingTableReq')
120-
cy.get('[data-cy="fileActionImportButton"]').click({ force: true })
190+
cy.get('[data-cy="fileActionImportButton"]').click({force: true})
121191
cy.wait('@importExistingTableReq').its('response.statusCode').should('equal', 200)
192+
193+
cy.get('[data-cy="importResultColumnsFound"]').should('contain.text', '4')
194+
cy.get('[data-cy="importResultColumnsMatch"]').should('contain.text', '4')
195+
cy.get('[data-cy="importResultColumnsCreated"]').should('contain.text', '0')
196+
cy.get('[data-cy="importResultRowsInserted"]').should('contain.text', '3')
197+
cy.get('[data-cy="importResultParsingErrors"]').should('contain.text', '0')
198+
cy.get('[data-cy="importResultRowErrors"]').should('contain.text', '0')
122199
})
123200

124201
})

cypress/e2e/tables-table.cy.js

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ describe('Manage a table', () => {
3737
})
3838

3939
it('Create with import', () => {
40-
cy.uploadFile('test-import.csv', 'text/csv')
40+
cy.uploadFile('test-import-small.csv', 'text/csv')
4141
cy.get('.icon-loading').should('not.exist')
4242
cy.get('[data-cy="navigationCreateTableIcon"]').click({ force: true })
4343
// should type before selecting the table type tile
@@ -51,9 +51,15 @@ describe('Manage a table', () => {
5151
cy.get('.file-picker button span').contains('Import').click()
5252
cy.get('.modal__content button').contains('Preview').click()
5353
cy.get('.file_import__preview tbody tr').should('have.length', 4)
54-
cy.intercept({ method: 'POST', url: '**/apps/tables/import/table/*/jobs'}).as('importUploadReq')
54+
cy.intercept({ method: 'POST', url: '**/apps/tables/import/table/*'}).as('importUploadReq')
5555
cy.get('.modal__content button').contains('Import').scrollIntoView().click()
56-
cy.wait('@importUploadReq').its('response.statusCode').should('equal', 200)
56+
cy.wait('@importUploadReq')
57+
cy.get('[data-cy="importResultColumnsFound"]').should('contain.text', '4')
58+
cy.get('[data-cy="importResultColumnsMatch"]').should('contain.text', '0')
59+
cy.get('[data-cy="importResultColumnsCreated"]').should('contain.text', '4')
60+
cy.get('[data-cy="importResultRowsInserted"]').should('contain.text', '3')
61+
cy.get('[data-cy="importResultParsingErrors"]').should('contain.text', '0')
62+
cy.get('[data-cy="importResultRowErrors"]').should('contain.text', '0')
5763
})
5864

5965
it('Update description', () => {

0 commit comments

Comments
 (0)