diff --git a/package-lock.json b/package-lock.json index db77c6049b..02938df125 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2229,6 +2229,16 @@ "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", "dev": true }, + "adler-32": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/adler-32/-/adler-32-1.2.0.tgz", + "integrity": "sha1-aj5r8KY5ALoVZSgIyxXGgT0aXyU=", + "dev": true, + "requires": { + "exit-on-epipe": "~1.0.1", + "printj": "~1.1.0" + } + }, "agent-base": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.3.0.tgz", @@ -2778,6 +2788,42 @@ "lodash": "^4.17.15" } }, + "cfb": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/cfb/-/cfb-1.2.1.tgz", + "integrity": "sha512-wT2ScPAFGSVy7CY+aauMezZBnNrfnaLSrxHUHdea+Td/86vrk6ZquggV+ssBR88zNs0OnBkL2+lf9q0K+zVGzQ==", + "dev": true, + "requires": { + "adler-32": "~1.3.0", + "crc-32": "~1.2.0", + "printj": "~1.3.0" + }, + "dependencies": { + "adler-32": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/adler-32/-/adler-32-1.3.0.tgz", + "integrity": "sha512-f5nltvjl+PRUh6YNfUstRaXwJxtfnKEWhAWWlmKvh+Y3J2+98a0KKVYDEhz6NdKGqswLhjNGznxfSsZGOvOd9g==", + "dev": true, + "requires": { + "printj": "~1.2.2" + }, + "dependencies": { + "printj": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/printj/-/printj-1.2.3.tgz", + "integrity": "sha512-sanczS6xOJOg7IKDvi4sGOUOe7c1tsEzjwlLFH/zgwx/uyImVM9/rgBkc8AfiQa/Vg54nRd8mkm9yI7WV/O+WA==", + "dev": true + } + } + }, + "printj": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/printj/-/printj-1.3.0.tgz", + "integrity": "sha512-017o8YIaz8gLhaNxRB9eBv2mWXI2CtzhPJALnQTP+OPpuUfP0RMWqr/mHCzqVeu1AQxfzSfAtAq66vKB8y7Lzg==", + "dev": true + } + } + }, "chalk": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", @@ -3022,6 +3068,12 @@ "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", "dev": true }, + "codepage": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/codepage/-/codepage-1.15.0.tgz", + "integrity": "sha512-3g6NUTPd/YtuuGrhMnOMRjFc+LJw/bnMp3+0r/Wcz3IXUuCosKRJvMphm5+Q+bvTVGcJJuRvVLuYba+WojaFaA==", + "dev": true + }, "collect-all": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/collect-all/-/collect-all-1.0.4.tgz", @@ -3570,6 +3622,16 @@ "parse-json": "^4.0.0" } }, + "crc-32": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.0.tgz", + "integrity": "sha512-1uBwHxF+Y/4yF5G48fwnKq6QsIXheor3ZLPT80yGBV1oEUwpPojlEhQbWKVw1VwcTQyMGHK1/XMmTjmlsmTTGA==", + "dev": true, + "requires": { + "exit-on-epipe": "~1.0.1", + "printj": "~1.1.0" + } + }, "cross-env": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-env/-/cross-env-7.0.3.tgz", @@ -4112,6 +4174,12 @@ "integrity": "sha1-8FyiM7SMBdVP/wd2XfhQfpXAL/g=", "dev": true }, + "exit-on-epipe": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/exit-on-epipe/-/exit-on-epipe-1.0.1.tgz", + "integrity": "sha512-h2z5mrROTxce56S+pnvAV890uu7ls7f1kEvVGJbw1OlFH3/mlJ5bkXu0KRyW94v37zzHPiUd55iLn3DA7TjWpw==", + "dev": true + }, "expand-brackets": { "version": "2.1.4", "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", @@ -4492,6 +4560,12 @@ "mime-types": "^2.1.12" } }, + "frac": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/frac/-/frac-1.1.2.tgz", + "integrity": "sha512-w/XBfkibaTl3YDqASwfDUqkna4Z2p9cFSr1aHDt0WoMTECnRfBOv2WArlZILlqgWlmdIlALXGpM2AOhEk5W3IA==", + "dev": true + }, "fragment-cache": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", @@ -4511,6 +4585,12 @@ "readable-stream": "^2.0.0" } }, + "fs": { + "version": "0.0.1-security", + "resolved": "https://registry.npmjs.org/fs/-/fs-0.0.1-security.tgz", + "integrity": "sha1-invTcYa23d84E/I4WLV+yq9eQdQ=", + "dev": true + }, "fs-extra": { "version": "9.1.0", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", @@ -7800,6 +7880,12 @@ "integrity": "sha512-FFw039TmrBqFK8ma/7OL3sDz/VytdtJr044/QUJtH0wK9lb9jLq9tJyIxUwtQJHwar2BqtiA4iCWSwo9JLkzFg==", "dev": true }, + "printj": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/printj/-/printj-1.1.2.tgz", + "integrity": "sha512-zA2SmoLaxZyArQTOPj5LXecR+RagfPSU5Kw1qP+jkWeNlrq+eJZyY2oS68SU1Z/7/myXM4lo9716laOFAVStCQ==", + "dev": true + }, "process-nextick-args": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", @@ -8395,6 +8481,12 @@ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", "dev": true }, + "scriptjs": { + "version": "2.5.9", + "resolved": "https://registry.npmjs.org/scriptjs/-/scriptjs-2.5.9.tgz", + "integrity": "sha512-qGVDoreyYiP1pkQnbnFAUIS5AjenNwwQBdl7zeos9etl+hYKWahjRTfzAZZYBv5xNHx7vNKCmaLDQZ6Fr2AEXg==", + "dev": true + }, "semver": { "version": "6.3.0", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", @@ -8794,6 +8886,15 @@ "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", "dev": true }, + "ssf": { + "version": "0.11.2", + "resolved": "https://registry.npmjs.org/ssf/-/ssf-0.11.2.tgz", + "integrity": "sha512-+idbmIXoYET47hH+d7dfm2epdOMUDjqcB4648sTZ+t2JwoyBFL/insLfB/racrDmsKB3diwsDA696pZMieAC5g==", + "dev": true, + "requires": { + "frac": "~1.1.2" + } + }, "sshpk": { "version": "1.16.1", "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz", @@ -9726,6 +9827,18 @@ } } }, + "wmf": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wmf/-/wmf-1.0.2.tgz", + "integrity": "sha512-/p9K7bEh0Dj6WbXg4JG0xvLQmIadrner1bi45VMJTfnbVHsc7yIajZyoSoK60/dtVBs12Fm6WkUI5/3WAVsNMw==", + "dev": true + }, + "word": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/word/-/word-0.3.0.tgz", + "integrity": "sha512-OELeY0Q61OXpdUfTp+oweA/vtLVg5VDOXh+3he3PNzLGG/y0oylSOC1xRVj0+l4vQ3tj/bB1HVHv1ocXkQceFA==", + "dev": true + }, "wordwrap": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", @@ -9872,6 +9985,21 @@ } } }, + "xlsx": { + "version": "0.17.4", + "resolved": "https://registry.npmjs.org/xlsx/-/xlsx-0.17.4.tgz", + "integrity": "sha512-9aKt8g9ZLP0CUdBX8L5xnoMDFwSiLI997eQnDThCaqQMYB9AEBIRzblSSNN/ICMGLYIHUO3VKaItcedZJ3ijIg==", + "dev": true, + "requires": { + "adler-32": "~1.2.0", + "cfb": "^1.1.4", + "codepage": "~1.15.0", + "crc-32": "~1.2.0", + "ssf": "~0.11.2", + "wmf": "~1.0.1", + "word": "~0.3.0" + } + }, "xmlcreate": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/xmlcreate/-/xmlcreate-2.0.3.tgz", diff --git a/package.json b/package.json index dcb1f80975..2ff9abee12 100644 --- a/package.json +++ b/package.json @@ -6,8 +6,11 @@ "cypress": "^7.3.0", "cypress-file-upload": "^5.0.8", "cypress-iframe": "^1.0.1", + "fs": "0.0.1-security", "jsdoc-to-markdown": "^5.0.3", - "lerna": "^3.20.1" + "lerna": "^3.20.1", + "scriptjs": "^2.5.9", + "xlsx": "^0.17.4" }, "scripts": { "start:api": "cd ./packages/nocodb; npm install; npm run watch:run", diff --git a/packages/nc-gui/components/templates/createProjectFromTemplateBtn.vue b/packages/nc-gui/components/templates/createProjectFromTemplateBtn.vue index c47f6ca447..d96dfc3ff0 100644 --- a/packages/nc-gui/components/templates/createProjectFromTemplateBtn.vue +++ b/packages/nc-gui/components/templates/createProjectFromTemplateBtn.vue @@ -124,7 +124,6 @@ export default { let total = 0; let progress = 0 console.log(this.importData) - debugger await Promise.all(Object.entries(this.importData).map(v => (async([table, data]) => { await this.$store.dispatch('meta/ActLoadMeta', { tn: `${prefix}${table}`, project_id: projectId diff --git a/scripts/cypress/fixtures/sampleFiles/simple.xlsx b/scripts/cypress/fixtures/sampleFiles/simple.xlsx new file mode 100644 index 0000000000..abf6adcf3a Binary files /dev/null and b/scripts/cypress/fixtures/sampleFiles/simple.xlsx differ diff --git a/scripts/cypress/integration/common/6g_base_share.js b/scripts/cypress/integration/common/6g_base_share.js index 4005f32c7a..b938ccf0f8 100644 --- a/scripts/cypress/integration/common/6g_base_share.js +++ b/scripts/cypress/integration/common/6g_base_share.js @@ -89,15 +89,17 @@ style="background: transparent; "> // open iFrame html cy.visit('scripts/cypress/fixtures/sampleFiles/iFrame.html') - cy.get('.nc-embed') + // wait for iFrame to load cy.frameLoaded('.nc-embed') + // validation for base menu opitons cy.iframe().find('.nc-project-tree').should('exist') cy.iframe().find('.nc-fields-menu-btn').should('exist') cy.iframe().find('.nc-sort-menu-btn').should('exist') cy.iframe().find('.nc-filter-menu-btn').should('exist') cy.iframe().find('.nc-actions-menu-btn').should('exist') + // validate data (row-1) mainPage.getIFrameCell('FirstName', 1).contains("PENELOPE").should('exist') mainPage.getIFrameCell('LastName', 1).contains("GUINESS").should('exist') }) diff --git a/scripts/cypress/integration/common/7a_create_project_from_excel.js b/scripts/cypress/integration/common/7a_create_project_from_excel.js new file mode 100644 index 0000000000..4b4879fe13 --- /dev/null +++ b/scripts/cypress/integration/common/7a_create_project_from_excel.js @@ -0,0 +1,143 @@ + +// Cypress test suite: Project creation using EXCEL +// + +import { projectsPage } from "../../support/page_objects/navigation" +import { mainPage } from "../../support/page_objects/mainPage" +import { staticProjects, roles, isTestSuiteActive } from "../../support/page_objects/projectConstants" +// import fs from "fs" + +// if (typeof require !== 'undefined') XLSX = require('xlsx'); +// let filepath = `sampleFiles/simple.xlsx` + +// let workbook + +// const getSheetList = (wb) => { +// return wb.SheetNames +// } + +// const getRow = (sheet, rowIdx) => { +// let sheetData = XLSX.utils.sheet_to_json(workbook.Sheets[sheet], { +// header: 1, +// blankrows: false +// }); + +// return sheetData[rowIdx] +// } + +// // https://stackoverflow.com/questions/40630606/how-to-read-only-column-a-value-from-excel-using-nodejs +// const getColumn = (sheet, colIdx) => { +// let columnA = [] +// const worksheet = workbook.Sheets[sheet]; +// for (let z in worksheet) { +// if (z.toString()[0] === colIdx) { +// columnA.push(worksheet[z].v); +// } +// } +// return columnA +// } + +// const getCell = (sheet, cellIdx) => { +// const worksheet = workbook.Sheets[sheet]; +// var desired_cell = worksheet[cellIdx]; +// desired_value = (desired_cell ? desired_cell.v : undefined); +// return desired_value +// } + + +export const genTest = (type, xcdb) => { + if (!isTestSuiteActive(type, xcdb)) return; + + describe(`Import from excel`, () => { + + it('Admin SignUp', () => { + cy.waitForSpinners(); + cy.signinOrSignup(roles.owner.credentials) + cy.wait(2000) + }) + + it(``, () => { + // cy.readFile('simple.xlsx').then((content) => { + // workbook = XLSX.read(content) + + // cy.log(workbook) + + // cy.log(getSheetList(workbook)) + // cy.log(getRow('Sheet2', 1)) + // cy.log(getColumn('Sheet2', 'A')) + // }) + // cy.task('readXlsx', { file: 'simple.xlsx', sheet: "Sheet2" }).then((rows) => { + // cy.log(rows) + // // expect(rows.length).to.equal(543) + // // expect(rows[0]["column name"]).to.equal(11060) + // }) + + cy.task('readSheetList', { file: 'simple.xlsx' }).then((rows) => { + cy.log(rows) + // expect(rows.length).to.equal(543) + // expect(rows[0]["column name"]).to.equal(11060) + }) + }) + + it.skip('Upload excel as template', () => { + + mainPage.toolBarTopLeft(mainPage.HOME).click() + + // click on "New Project" + cy.get(':nth-child(5) > .v-btn', { timeout: 20000 }).click() + + // Subsequent form, select (+ Create) option + cy.get('.nc-create-project-from-excel', { timeout: 20000 }).click({ force: true }) + + cy.get('.nc-excel-import-input').attachFile(filepath) + cy.get('.nc-btn-use-template', { timeout: 120000 }).should('exist') + + // validate pre-load template page + cy.getActiveContentModal().find('.v-expansion-panel').then((panel) => { + // cy.log(panel.length) + for (let i = 0; i < panel.length; i++) { + // cy.log(panel[i]) + cy.wrap(panel[i]).find('.title').then((blk) => { + cy.log(blk.text().trim()) + }) + cy.wrap(panel[i]).find('.mdi-chevron-down').click() + cy.wait(1000) + cy.get('.v-data-table').find('tr:visible').then((row) => { + // cy.log(row) + for (let j = 2; j < row.length; j++) { + cy.wrap(row[j]).find('[placeholder="Column name"]').then((obj) => { + cy.log(obj[0].value) + }) + cy.wrap(row[j]).find('span.caption').then((obj) => { + cy.log(obj[0].innerText) + }) + } + }) + cy.wrap(panel[i]).find('.mdi-chevron-down').click() + } + }) + }) + }) +} + +/** + * @copyright Copyright (c) 2021, Xgene Cloud Ltd + * + * @author Raju Udava + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ diff --git a/scripts/cypress/plugins/index.js b/scripts/cypress/plugins/index.js index fac85cab0f..76d8b3b10a 100644 --- a/scripts/cypress/plugins/index.js +++ b/scripts/cypress/plugins/index.js @@ -40,3 +40,14 @@ module.exports = (on, config) => { }) } + +// https://stackoverflow.com/questions/61934443/read-excel-files-in-cypress +const readXlsx = require('./read-xlsx') + +module.exports = (on, config) => { + on('task', { + 'readXlsx': readXlsx.read, + 'readSheetList': readXlsx.sheetList + }) +} + diff --git a/scripts/cypress/plugins/read-xlsx.js b/scripts/cypress/plugins/read-xlsx.js new file mode 100644 index 0000000000..ee08fef3f8 --- /dev/null +++ b/scripts/cypress/plugins/read-xlsx.js @@ -0,0 +1,23 @@ +// https://stackoverflow.com/questions/61934443/read-excel-files-in-cypress + +const fs = require('fs'); +const XLSX = require('xlsx'); + +const read = ({file, sheet}) => { + const buf = fs.readFileSync(file); + const workbook = XLSX.read(buf, { type: 'buffer' }); + const rows = XLSX.utils.sheet_to_json(workbook.Sheets[sheet]); + return rows +} + +const sheetList = ({file}) => { + const buf = fs.readFileSync(file); + const workbook = XLSX.read(buf, { type: 'buffer' }); + const rows = workbook.SheetNames + return rows +} + +module.exports = { + read, + sheetList, +} \ No newline at end of file diff --git a/scripts/cypress/support/page_objects/mainPage.js b/scripts/cypress/support/page_objects/mainPage.js index 0beb19d89d..b3cb248f16 100644 --- a/scripts/cypress/support/page_objects/mainPage.js +++ b/scripts/cypress/support/page_objects/mainPage.js @@ -321,6 +321,19 @@ export class _mainPage { getIFrameCell = (columnHeader, cellNumber) => { return cy.iframe().find(`tbody > :nth-child(${cellNumber}) > [data-col="${columnHeader}"]`) } + + // https://docs.cypress.io/guides/core-concepts/variables-and-aliases#Sharing-Context + getDatatype = (tableName, columnName) => { + cy.window().then(win => { + const col = win.$nuxt.$store.state.meta.metas[tableName].columns + let dataType = '' + col.forEach(element => { + if(element.cn == columnName) + dataType = element.uidt + }) + cy.wrap(dataType).as('ncDatatype') + }) + } }