diff --git a/packages/nc-gui/components/project/spreadsheet/components/MoreActions.vue b/packages/nc-gui/components/project/spreadsheet/components/MoreActions.vue
index c730db9227..65c41dda58 100644
--- a/packages/nc-gui/components/project/spreadsheet/components/MoreActions.vue
+++ b/packages/nc-gui/components/project/spreadsheet/components/MoreActions.vue
@@ -28,6 +28,15 @@
+
+
+ mdi-download-outline
+
+
+ {{ $t('activity.downloadExcel') }}
+
+
+
import FileSaver from 'file-saver';
+import * as XLSX from 'xlsx';
import { ExportTypes } from 'nocodb-sdk';
import DropOrSelectFileModal from '~/components/import/DropOrSelectFileModal';
import ColumnMappingModal from '~/components/project/spreadsheet/components/importExport/ColumnMappingModal';
@@ -220,51 +230,34 @@ export default {
})
);
},
- async exportCsv() {
+ async exportExcel() {
let offset = 0;
let c = 1;
-
try {
while (!isNaN(offset) && offset > -1) {
- let res;
- if (this.publicViewId) {
- res = await this.$api.public.csvExport(this.publicViewId, ExportTypes.CSV, {
- responseType: 'blob',
- query: {
- fields:
- this.queryParams &&
- this.queryParams.fieldsOrder &&
- this.queryParams.fieldsOrder.filter(c => this.queryParams.showFields[c]),
- offset,
- sortArrJson: JSON.stringify(
- this.reqPayload &&
- this.reqPayload.sorts &&
- this.reqPayload.sorts.map(({ fk_column_id, direction }) => ({
- direction,
- fk_column_id,
- }))
- ),
- filterArrJson: JSON.stringify(this.reqPayload && this.reqPayload.filters),
- },
- headers: {
- 'xc-password': this.reqPayload && this.reqPayload.password,
- },
- });
+ const res = await this.getExportData({ offset, exportType: ExportTypes.EXCEL, responseType: 'base64' });
+ const workbook = XLSX.read(res.data, { type: 'base64' });
+ XLSX.writeFile(workbook, `${this.meta.title}_exported_${c++}.xlsx`);
+
+ offset = +res.headers['nc-export-offset'];
+ if (offset > -1) {
+ this.$toast.info('Downloading more files').goAway(3000);
} else {
- res = await this.$api.dbViewRow.export(
- 'noco',
- this.projectName,
- this.meta.title,
- this.selectedView.title,
- ExportTypes.CSV,
- {
- responseType: 'blob',
- query: {
- offset,
- },
- }
- );
+ this.$toast.success('Successfully exported all table data').goAway(3000);
}
+ }
+ } catch (e) {
+ console.log(e);
+ this.$toast.error(e.message).goAway(3000);
+ }
+ },
+ async exportCsv() {
+ let offset = 0;
+ let c = 1;
+
+ try {
+ while (!isNaN(offset) && offset > -1) {
+ const res = await this.getExportData({ offset, exportType: ExportTypes.CSV, responseType: 'blob' })
const { data } = res;
offset = +res.headers['nc-export-offset'];
@@ -281,6 +274,48 @@ export default {
this.$toast.error(e.message).goAway(3000);
}
},
+ async getExportData({ offset, exportType, responseType }) {
+ let res;
+ if (this.publicViewId) {
+ res = await this.$api.public.csvExport(this.publicViewId, exportType, {
+ responseType,
+ query: {
+ fields:
+ this.queryParams &&
+ this.queryParams.fieldsOrder &&
+ this.queryParams.fieldsOrder.filter(c => this.queryParams.showFields[c]),
+ offset,
+ sortArrJson: JSON.stringify(
+ this.reqPayload &&
+ this.reqPayload.sorts &&
+ this.reqPayload.sorts.map(({ fk_column_id, direction }) => ({
+ direction,
+ fk_column_id,
+ }))
+ ),
+ filterArrJson: JSON.stringify(this.reqPayload && this.reqPayload.filters),
+ },
+ headers: {
+ 'xc-password': this.reqPayload && this.reqPayload.password,
+ },
+ });
+ } else {
+ res = await this.$api.dbViewRow.export(
+ 'noco',
+ this.projectName,
+ this.meta.title,
+ this.selectedView.title,
+ exportType,
+ {
+ responseType,
+ query: {
+ offset,
+ },
+ }
+ );
+ }
+ return res;
+ },
async importData(columnMappings) {
try {
const data = this.parsedCsv.data;
diff --git a/packages/nc-gui/lang/da.json b/packages/nc-gui/lang/da.json
index ac48c94ae5..76d047bbba 100644
--- a/packages/nc-gui/lang/da.json
+++ b/packages/nc-gui/lang/da.json
@@ -309,6 +309,7 @@
"importExcel": "Import Excel.",
"importCSV": "Import CSV.",
"downloadCSV": "Download som CSV.",
+ "downloadExcel": "Download som XLSX.",
"uploadCSV": "Upload CSV.",
"import": "Importere",
"importMetadata": "Import metadata.",
diff --git a/packages/nc-gui/lang/de.json b/packages/nc-gui/lang/de.json
index a4e332aa4d..d8b38a3e20 100644
--- a/packages/nc-gui/lang/de.json
+++ b/packages/nc-gui/lang/de.json
@@ -309,6 +309,7 @@
"importExcel": "Import Excel",
"importCSV": "Import CSV",
"downloadCSV": "Download als CSV",
+ "downloadExcel": "Download als XLSX",
"uploadCSV": "Hochladen CSV",
"import": "Importieren",
"importMetadata": "Metadaten importieren",
diff --git a/packages/nc-gui/lang/en.json b/packages/nc-gui/lang/en.json
index 363d371b3a..609f17d494 100644
--- a/packages/nc-gui/lang/en.json
+++ b/packages/nc-gui/lang/en.json
@@ -309,6 +309,7 @@
"importExcel": "Import Excel",
"importCSV": "Import CSV",
"downloadCSV": "Download as CSV",
+ "downloadExcel": "Download as XLSX",
"uploadCSV": "Upload CSV",
"import": "Import",
"importMetadata": "Import Metadata",
diff --git a/packages/nc-gui/lang/es.json b/packages/nc-gui/lang/es.json
index 22a6e992ab..6fdb219a4b 100644
--- a/packages/nc-gui/lang/es.json
+++ b/packages/nc-gui/lang/es.json
@@ -309,6 +309,7 @@
"importExcel": "Importar Excel",
"importCSV": "Import CSV",
"downloadCSV": "Descargar como CSV",
+ "downloadExcel": "Descargar como XLSX",
"uploadCSV": "Subir CSV",
"import": "Importar",
"importMetadata": "Importar metadatos",
diff --git a/packages/nc-gui/lang/fa.json b/packages/nc-gui/lang/fa.json
index 335e034da4..0e564a1a07 100644
--- a/packages/nc-gui/lang/fa.json
+++ b/packages/nc-gui/lang/fa.json
@@ -309,6 +309,7 @@
"importExcel": "وارد کردن فایل Excel",
"importCSV": "Import CSV",
"downloadCSV": "دانلود بهعنوان CSV",
+ "downloadXLSX": "دانلود بهعنوان XLSX",
"uploadCSV": "بارگذاری CSV",
"import": "وارد کردن",
"importMetadata": "وارد کردن فراداده",
diff --git a/packages/nc-gui/lang/fi.json b/packages/nc-gui/lang/fi.json
index 035045e498..8ca1bf26d3 100644
--- a/packages/nc-gui/lang/fi.json
+++ b/packages/nc-gui/lang/fi.json
@@ -309,6 +309,7 @@
"importExcel": "Tuonti excel",
"importCSV": "Import CSV",
"downloadCSV": "Lataa CSV",
+ "downloadXLSX": "Lataa XLSX",
"uploadCSV": "Lataa CSV",
"import": "Tuonti",
"importMetadata": "Tuo metatieto",
diff --git a/packages/nc-gui/lang/fr.json b/packages/nc-gui/lang/fr.json
index 9663597c8d..d319b68822 100644
--- a/packages/nc-gui/lang/fr.json
+++ b/packages/nc-gui/lang/fr.json
@@ -309,6 +309,7 @@
"importExcel": "Importer depuis Excel",
"importCSV": "Import CSV",
"downloadCSV": "Télécharger comme CSV",
+ "downloadExcel": "Télécharger comme XLSX",
"uploadCSV": "Téléverser un CSV",
"import": "Importer",
"importMetadata": "Importer les métadonnées",
diff --git a/packages/nc-gui/lang/hr.json b/packages/nc-gui/lang/hr.json
index 5be380f930..cad1fea145 100644
--- a/packages/nc-gui/lang/hr.json
+++ b/packages/nc-gui/lang/hr.json
@@ -309,6 +309,7 @@
"importExcel": "Uvoz Excel",
"importCSV": "Import CSV",
"downloadCSV": "Preuzmite kao CSV",
+ "downloadExcel": "Preuzmite kao XLSX",
"uploadCSV": "Prenesite CSV",
"import": "Uvoz",
"importMetadata": "Uvoz metapodataka",
diff --git a/packages/nc-gui/lang/id.json b/packages/nc-gui/lang/id.json
index 4704e039ca..0c133f39b1 100644
--- a/packages/nc-gui/lang/id.json
+++ b/packages/nc-gui/lang/id.json
@@ -309,6 +309,7 @@
"importExcel": "Impor Excel.",
"importCSV": "Import CSV",
"downloadCSV": "Unduh sebagai CSV.",
+ "downloadExcel": "Unduh sebagai XLSX.",
"uploadCSV": "Unggah CSV.",
"import": "Impor",
"importMetadata": "Impor Metadata.",
diff --git a/packages/nc-gui/lang/it_IT.json b/packages/nc-gui/lang/it_IT.json
index 36e925f1b9..fd92653acb 100644
--- a/packages/nc-gui/lang/it_IT.json
+++ b/packages/nc-gui/lang/it_IT.json
@@ -309,6 +309,7 @@
"importExcel": "Importa Excel.",
"importCSV": "Import CSV",
"downloadCSV": "Scarica come CSV.",
+ "downloadExcel": "Scarica come XLSX.",
"uploadCSV": "Carica CSV.",
"import": "Importa",
"importMetadata": "Importa metadati",
diff --git a/packages/nc-gui/lang/iw.json b/packages/nc-gui/lang/iw.json
index 45e373e57d..0ae3bdd7db 100644
--- a/packages/nc-gui/lang/iw.json
+++ b/packages/nc-gui/lang/iw.json
@@ -309,6 +309,7 @@
"importExcel": "ייבוא Excel",
"importCSV": "Import CSV",
"downloadCSV": "הורד כמו CSV.",
+ "downloadExcel": "הורד כמו XLSX.",
"uploadCSV": "העלה CSV.",
"import": "יְבוּא",
"importMetadata": "ייבוא מטא נתונים",
diff --git a/packages/nc-gui/lang/ja.json b/packages/nc-gui/lang/ja.json
index 40e5792eb1..45a356abf8 100644
--- a/packages/nc-gui/lang/ja.json
+++ b/packages/nc-gui/lang/ja.json
@@ -309,6 +309,7 @@
"importExcel": "エクセルファイルをインポート",
"importCSV": "Import CSV",
"downloadCSV": "CSVをダウンロード",
+ "downloadExcel": "XLSXをダウンロード",
"uploadCSV": "CSVをアップロード",
"import": "インポート",
"importMetadata": "メタデータをインポート",
diff --git a/packages/nc-gui/lang/ko.json b/packages/nc-gui/lang/ko.json
index a0f0259d99..af75a190bd 100644
--- a/packages/nc-gui/lang/ko.json
+++ b/packages/nc-gui/lang/ko.json
@@ -309,6 +309,7 @@
"importExcel": "엑셀 가져오기",
"importCSV": "CSV 가져오기",
"downloadCSV": "CSV 다운로드",
+ "downloadExcel": "XLSX 다운로드",
"uploadCSV": "CSV 업로드",
"import": "가져오기",
"importMetadata": "메타 데이터 가져오기",
diff --git a/packages/nc-gui/lang/lv.json b/packages/nc-gui/lang/lv.json
index f2163b25e8..81d12e1e31 100644
--- a/packages/nc-gui/lang/lv.json
+++ b/packages/nc-gui/lang/lv.json
@@ -309,6 +309,7 @@
"importExcel": "Importēt Excel",
"importCSV": "Import CSV",
"downloadCSV": "Lejupielādēt kā CSV",
+ "downloadExcel": "Lejupielādēt kā XLSX",
"uploadCSV": "Augšupielādēt CSV",
"import": "Importēt",
"importMetadata": "Importēt metadatus",
diff --git a/packages/nc-gui/lang/nl.json b/packages/nc-gui/lang/nl.json
index 1e643d36b8..14eca36408 100644
--- a/packages/nc-gui/lang/nl.json
+++ b/packages/nc-gui/lang/nl.json
@@ -309,6 +309,7 @@
"importExcel": "Excel importeren",
"importCSV": "Import CSV",
"downloadCSV": "Download als CSV",
+ "downloadExcel": "Download als XLSX",
"uploadCSV": "Upload CSV",
"import": "Importeren",
"importMetadata": "Importeer Metadata",
diff --git a/packages/nc-gui/lang/no.json b/packages/nc-gui/lang/no.json
index 3714b6dddf..1a9ef09ec3 100644
--- a/packages/nc-gui/lang/no.json
+++ b/packages/nc-gui/lang/no.json
@@ -309,6 +309,7 @@
"importExcel": "Importer Excel.",
"importCSV": "Import CSV",
"downloadCSV": "Last ned som CSV.",
+ "downloadExcel": "Last ned som XLSX.",
"uploadCSV": "Last opp CSV.",
"import": "Importer",
"importMetadata": "Importer metadata",
diff --git a/packages/nc-gui/lang/pl.json b/packages/nc-gui/lang/pl.json
index 051d85875e..0aaaa91a56 100644
--- a/packages/nc-gui/lang/pl.json
+++ b/packages/nc-gui/lang/pl.json
@@ -309,6 +309,7 @@
"importExcel": "Importuj Excel.",
"importCSV": "Import CSV",
"downloadCSV": "Pobierz jako CSV.",
+ "downloadExcel": "Pobierz jako XLSX.",
"uploadCSV": "Prześlij CSV.",
"import": "Import",
"importMetadata": "Importuj metadane",
diff --git a/packages/nc-gui/lang/pt.json b/packages/nc-gui/lang/pt.json
index 8961d7bdd6..5e41c2b877 100644
--- a/packages/nc-gui/lang/pt.json
+++ b/packages/nc-gui/lang/pt.json
@@ -309,6 +309,7 @@
"importExcel": "Importar Excel.",
"importCSV": "Import CSV",
"downloadCSV": "Baixe como CSV.",
+ "downloadExcel": "Baixe como XLSX.",
"uploadCSV": "Carregar CSV.",
"import": "Importar",
"importMetadata": "Importar Metadados",
diff --git a/packages/nc-gui/lang/pt_BR.json b/packages/nc-gui/lang/pt_BR.json
index cb24beebc0..20201e13b5 100644
--- a/packages/nc-gui/lang/pt_BR.json
+++ b/packages/nc-gui/lang/pt_BR.json
@@ -309,6 +309,7 @@
"importExcel": "Importar Excel.",
"importCSV": "Import CSV",
"downloadCSV": "Baixe como CSV.",
+ "downloadExcel": "Baixe como XLSX.",
"uploadCSV": "Carregar CSV.",
"import": "Importar",
"importMetadata": "Importar Metadados",
diff --git a/packages/nc-gui/lang/ru.json b/packages/nc-gui/lang/ru.json
index 5ab0ef2225..c3e3934d8c 100644
--- a/packages/nc-gui/lang/ru.json
+++ b/packages/nc-gui/lang/ru.json
@@ -308,6 +308,7 @@
"importExcel": "Импорт из Excel",
"importCSV": "Import CSV",
"downloadCSV": "Скачать как CSV.",
+ "downloadExcel": "Скачать как XLSX.",
"uploadCSV": "Загрузить CSV.",
"import": "Импортировать",
"importMetadata": "Импорт метаданных",
diff --git a/packages/nc-gui/lang/sl.json b/packages/nc-gui/lang/sl.json
index 9f56795611..28968cea06 100644
--- a/packages/nc-gui/lang/sl.json
+++ b/packages/nc-gui/lang/sl.json
@@ -309,6 +309,7 @@
"importExcel": "Uvoz Excel.",
"importCSV": "Import CSV",
"downloadCSV": "Prenesite kot CSV.",
+ "downloadExcel": "Prenesite kot XLSX.",
"uploadCSV": "Upload CSV.",
"import": "Uvozi",
"importMetadata": "Uvozi metapodatkov",
diff --git a/packages/nc-gui/lang/sv.json b/packages/nc-gui/lang/sv.json
index de5eede18e..914b8e432d 100644
--- a/packages/nc-gui/lang/sv.json
+++ b/packages/nc-gui/lang/sv.json
@@ -309,6 +309,7 @@
"importExcel": "Import excel",
"importCSV": "Import CSV",
"downloadCSV": "Hämta som CSV",
+ "downloadExcel": "Hämta som XLSX",
"uploadCSV": "Ladda upp CSV",
"import": "Importera",
"importMetadata": "Importera metadata",
diff --git a/packages/nc-gui/lang/th.json b/packages/nc-gui/lang/th.json
index 0a8cf296bb..6459bb5d76 100644
--- a/packages/nc-gui/lang/th.json
+++ b/packages/nc-gui/lang/th.json
@@ -309,6 +309,7 @@
"importExcel": "นำเข้า Excel",
"importCSV": "Import CSV",
"downloadCSV": "ดาวน์โหลดเป็น CSV",
+ "downloadExcel": "ดาวน์โหลดเป็น XLSX",
"uploadCSV": "อัปโหลด CSV",
"import": "นำเข้า",
"importMetadata": "เมทาดานำเข้า",
diff --git a/packages/nc-gui/lang/tr.json b/packages/nc-gui/lang/tr.json
index 79bbbe78d9..37938862e0 100644
--- a/packages/nc-gui/lang/tr.json
+++ b/packages/nc-gui/lang/tr.json
@@ -309,6 +309,7 @@
"importExcel": "Excel'i içe aktar",
"importCSV": "Import CSV",
"downloadCSV": "CSV olarak indir",
+ "downloadExcel": "XLSX olarak indir",
"uploadCSV": "CSV yükle",
"import": "İçe aktar",
"importMetadata": "Meta verilerini içe aktar",
diff --git a/packages/nc-gui/lang/uk.json b/packages/nc-gui/lang/uk.json
index 1446b367d0..dfb4ec2d17 100644
--- a/packages/nc-gui/lang/uk.json
+++ b/packages/nc-gui/lang/uk.json
@@ -309,6 +309,7 @@
"importExcel": "Імпорт Excel",
"importCSV": "Import CSV",
"downloadCSV": "Завантажити як CSV",
+ "downloadExcel": "Завантажити як XLSX",
"uploadCSV": "Завантажити CSV",
"import": "Імпортувати",
"importMetadata": "Імпорт метаданих",
diff --git a/packages/nc-gui/lang/vi.json b/packages/nc-gui/lang/vi.json
index cfe69a98b9..04fcc91e2e 100644
--- a/packages/nc-gui/lang/vi.json
+++ b/packages/nc-gui/lang/vi.json
@@ -309,6 +309,7 @@
"importExcel": "Nhập Excel.",
"importCSV": "Import CSV",
"downloadCSV": "Tải về dưới dạng CSV.",
+ "downloadExcel": "Tải về dưới dạng XLSX.",
"uploadCSV": "Tải lên CSV.",
"import": "Nhập khẩu",
"importMetadata": "Nhập siêu dữ liệu",
diff --git a/packages/nc-gui/lang/zh_CN.json b/packages/nc-gui/lang/zh_CN.json
index 38990ec059..cfb15971f4 100644
--- a/packages/nc-gui/lang/zh_CN.json
+++ b/packages/nc-gui/lang/zh_CN.json
@@ -309,6 +309,7 @@
"importExcel": "导入Excel",
"importCSV": "Import CSV",
"downloadCSV": "下载为CSV",
+ "downloadExcel": "下载为XLSX",
"uploadCSV": "上传CSV",
"import": "导入",
"importMetadata": "导入元数据",
diff --git a/packages/nc-gui/lang/zh_HK.json b/packages/nc-gui/lang/zh_HK.json
index 614c1babeb..aafd0be421 100644
--- a/packages/nc-gui/lang/zh_HK.json
+++ b/packages/nc-gui/lang/zh_HK.json
@@ -309,6 +309,7 @@
"importExcel": "導入Excel.",
"importCSV": "Import CSV",
"downloadCSV": "下載為CSV.",
+ "downloadExcel": "下載為XLSX.",
"uploadCSV": "上傳CSV.",
"import": "導出去file",
"importMetadata": "import metadata",
diff --git a/packages/nc-gui/lang/zh_TW.json b/packages/nc-gui/lang/zh_TW.json
index 9003a2d005..a1ffb8f999 100644
--- a/packages/nc-gui/lang/zh_TW.json
+++ b/packages/nc-gui/lang/zh_TW.json
@@ -309,6 +309,7 @@
"importExcel": "匯入 Excel",
"importCSV": "匯入 CSV",
"downloadCSV": "下載為 CSV",
+ "downloadExcel": "下載為 XLSX",
"uploadCSV": "上傳 CSV",
"import": "匯入",
"importMetadata": "匯入中繼資料",
@@ -517,4 +518,4 @@
"futureRelease": "即將推出!"
}
}
-}
\ No newline at end of file
+}
diff --git a/packages/nc-gui/package-lock.json b/packages/nc-gui/package-lock.json
index c6772c1483..47a28b25e5 100644
--- a/packages/nc-gui/package-lock.json
+++ b/packages/nc-gui/package-lock.json
@@ -56,7 +56,7 @@
"vuelidate": "^0.7.6",
"vuetify-datetime-picker": "^2.1.1",
"vuex-persistedstate": "^3.1.0",
- "xlsx": "^0.17.3",
+ "xlsx": "^0.17.5",
"xterm": "^4.8.1",
"xterm-addon-fit": "^0.4.0",
"xterm-addon-web-links": "^0.4.0"
diff --git a/packages/nc-gui/package.json b/packages/nc-gui/package.json
index 56a8b4fe42..be6c6cf232 100644
--- a/packages/nc-gui/package.json
+++ b/packages/nc-gui/package.json
@@ -60,7 +60,7 @@
"vuelidate": "^0.7.6",
"vuetify-datetime-picker": "^2.1.1",
"vuex-persistedstate": "^3.1.0",
- "xlsx": "^0.17.3",
+ "xlsx": "^0.17.5",
"xterm": "^4.8.1",
"xterm-addon-fit": "^0.4.0",
"xterm-addon-web-links": "^0.4.0"
diff --git a/packages/nocodb-sdk/src/lib/globals.ts b/packages/nocodb-sdk/src/lib/globals.ts
index 8c990d585e..b63424b42a 100644
--- a/packages/nocodb-sdk/src/lib/globals.ts
+++ b/packages/nocodb-sdk/src/lib/globals.ts
@@ -12,6 +12,7 @@ export enum RelationTypes {
}
export enum ExportTypes {
+ EXCEL = 'excel',
CSV = 'csv',
}
diff --git a/packages/nocodb/package-lock.json b/packages/nocodb/package-lock.json
index 464f750569..c7b690811c 100644
--- a/packages/nocodb/package-lock.json
+++ b/packages/nocodb/package-lock.json
@@ -100,7 +100,8 @@
"unique-names-generator": "^4.3.1",
"uuid": "^8.2.0",
"validator": "^13.1.1",
- "xc-core-ts": "^0.1.0"
+ "xc-core-ts": "^0.1.0",
+ "xlsx": "^0.18.5"
},
"devDependencies": {
"@bitjson/npm-scripts-info": "^1.0.0",
@@ -2501,6 +2502,14 @@
"integrity": "sha512-qQLMr+8o0WC4FZGQTcJiKBVC59JylcPSrTtk6usvmIDFUOCKegapy1VHQwRbFMOFyb/inzUVqHs+eMYKDM1YeQ==",
"dev": true
},
+ "node_modules/adler-32": {
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/adler-32/-/adler-32-1.3.1.tgz",
+ "integrity": "sha512-ynZ4w/nUUv5rrsR8UUGoe1VC9hZj6V5hU9Qw1HlMDJGEJw5S7TfTErWTjMys6M7vr0YWcPqs3qAr4ss0nDfP+A==",
+ "engines": {
+ "node": ">=0.8"
+ }
+ },
"node_modules/agent-base": {
"version": "6.0.2",
"resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz",
@@ -4387,6 +4396,18 @@
"integrity": "sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==",
"optional": true
},
+ "node_modules/cfb": {
+ "version": "1.2.2",
+ "resolved": "https://registry.npmjs.org/cfb/-/cfb-1.2.2.tgz",
+ "integrity": "sha512-KfdUZsSOw19/ObEWasvBP/Ac4reZvAGauZhs6S/gqNhXhI7cKwvlH7ulj+dOEYnca4bm4SGo8C1bTAQvnTjgQA==",
+ "dependencies": {
+ "adler-32": "~1.3.0",
+ "crc-32": "~1.2.0"
+ },
+ "engines": {
+ "node": ">=0.8"
+ }
+ },
"node_modules/chai": {
"version": "4.3.6",
"resolved": "https://registry.npmjs.org/chai/-/chai-4.3.6.tgz",
@@ -4926,6 +4947,14 @@
"node": ">=10"
}
},
+ "node_modules/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==",
+ "engines": {
+ "node": ">=0.8"
+ }
+ },
"node_modules/collection-visit": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz",
@@ -9887,6 +9916,14 @@
"node": ">= 0.6"
}
},
+ "node_modules/frac": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/frac/-/frac-1.1.2.tgz",
+ "integrity": "sha512-w/XBfkibaTl3YDqASwfDUqkna4Z2p9cFSr1aHDt0WoMTECnRfBOv2WArlZILlqgWlmdIlALXGpM2AOhEk5W3IA==",
+ "engines": {
+ "node": ">=0.8"
+ }
+ },
"node_modules/fragment-cache": {
"version": "0.2.1",
"resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz",
@@ -19930,6 +19967,17 @@
"node": ">= 0.6"
}
},
+ "node_modules/ssf": {
+ "version": "0.11.2",
+ "resolved": "https://registry.npmjs.org/ssf/-/ssf-0.11.2.tgz",
+ "integrity": "sha512-+idbmIXoYET47hH+d7dfm2epdOMUDjqcB4648sTZ+t2JwoyBFL/insLfB/racrDmsKB3diwsDA696pZMieAC5g==",
+ "dependencies": {
+ "frac": "~1.1.2"
+ },
+ "engines": {
+ "node": ">=0.8"
+ }
+ },
"node_modules/sshpk": {
"version": "1.17.0",
"resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.17.0.tgz",
@@ -24426,6 +24474,22 @@
"node": ">= 6.4.0"
}
},
+ "node_modules/wmf": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/wmf/-/wmf-1.0.2.tgz",
+ "integrity": "sha512-/p9K7bEh0Dj6WbXg4JG0xvLQmIadrner1bi45VMJTfnbVHsc7yIajZyoSoK60/dtVBs12Fm6WkUI5/3WAVsNMw==",
+ "engines": {
+ "node": ">=0.8"
+ }
+ },
+ "node_modules/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==",
+ "engines": {
+ "node": ">=0.8"
+ }
+ },
"node_modules/word-wrap": {
"version": "1.2.3",
"resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz",
@@ -24582,6 +24646,26 @@
"node": ">=0.10.0"
}
},
+ "node_modules/xlsx": {
+ "version": "0.18.5",
+ "resolved": "https://registry.npmjs.org/xlsx/-/xlsx-0.18.5.tgz",
+ "integrity": "sha512-dmg3LCjBPHZnQp5/F/+nnTa+miPJxUXB6vtk42YjBBKayDNagxGEeIdWApkYPOf3Z3pm3k62Knjzp7lMeTEtFQ==",
+ "dependencies": {
+ "adler-32": "~1.3.0",
+ "cfb": "~1.2.1",
+ "codepage": "~1.15.0",
+ "crc-32": "~1.2.1",
+ "ssf": "~0.11.2",
+ "wmf": "~1.0.1",
+ "word": "~0.3.0"
+ },
+ "bin": {
+ "xlsx": "bin/xlsx.njs"
+ },
+ "engines": {
+ "node": ">=0.8"
+ }
+ },
"node_modules/xml": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/xml/-/xml-1.0.1.tgz",
@@ -26624,6 +26708,11 @@
"integrity": "sha512-qQLMr+8o0WC4FZGQTcJiKBVC59JylcPSrTtk6usvmIDFUOCKegapy1VHQwRbFMOFyb/inzUVqHs+eMYKDM1YeQ==",
"dev": true
},
+ "adler-32": {
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/adler-32/-/adler-32-1.3.1.tgz",
+ "integrity": "sha512-ynZ4w/nUUv5rrsR8UUGoe1VC9hZj6V5hU9Qw1HlMDJGEJw5S7TfTErWTjMys6M7vr0YWcPqs3qAr4ss0nDfP+A=="
+ },
"agent-base": {
"version": "6.0.2",
"resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz",
@@ -28156,6 +28245,15 @@
"integrity": "sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==",
"optional": true
},
+ "cfb": {
+ "version": "1.2.2",
+ "resolved": "https://registry.npmjs.org/cfb/-/cfb-1.2.2.tgz",
+ "integrity": "sha512-KfdUZsSOw19/ObEWasvBP/Ac4reZvAGauZhs6S/gqNhXhI7cKwvlH7ulj+dOEYnca4bm4SGo8C1bTAQvnTjgQA==",
+ "requires": {
+ "adler-32": "~1.3.0",
+ "crc-32": "~1.2.0"
+ }
+ },
"chai": {
"version": "4.3.6",
"resolved": "https://registry.npmjs.org/chai/-/chai-4.3.6.tgz",
@@ -28569,6 +28667,11 @@
}
}
},
+ "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=="
+ },
"collection-visit": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz",
@@ -32481,6 +32584,11 @@
"resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz",
"integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow=="
},
+ "frac": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/frac/-/frac-1.1.2.tgz",
+ "integrity": "sha512-w/XBfkibaTl3YDqASwfDUqkna4Z2p9cFSr1aHDt0WoMTECnRfBOv2WArlZILlqgWlmdIlALXGpM2AOhEk5W3IA=="
+ },
"fragment-cache": {
"version": "0.2.1",
"resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz",
@@ -40312,6 +40420,14 @@
"resolved": "https://registry.npmjs.org/sqlstring/-/sqlstring-2.3.3.tgz",
"integrity": "sha512-qC9iz2FlN7DQl3+wjwn3802RTyjCx7sDvfQEXchwa6CWOx07/WVfh91gBmQ9fahw8snwGEWU3xGzOt4tFyHLxg=="
},
+ "ssf": {
+ "version": "0.11.2",
+ "resolved": "https://registry.npmjs.org/ssf/-/ssf-0.11.2.tgz",
+ "integrity": "sha512-+idbmIXoYET47hH+d7dfm2epdOMUDjqcB4648sTZ+t2JwoyBFL/insLfB/racrDmsKB3diwsDA696pZMieAC5g==",
+ "requires": {
+ "frac": "~1.1.2"
+ }
+ },
"sshpk": {
"version": "1.17.0",
"resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.17.0.tgz",
@@ -43869,6 +43985,16 @@
"triple-beam": "^1.3.0"
}
},
+ "wmf": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/wmf/-/wmf-1.0.2.tgz",
+ "integrity": "sha512-/p9K7bEh0Dj6WbXg4JG0xvLQmIadrner1bi45VMJTfnbVHsc7yIajZyoSoK60/dtVBs12Fm6WkUI5/3WAVsNMw=="
+ },
+ "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=="
+ },
"word-wrap": {
"version": "1.2.3",
"resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz",
@@ -43985,6 +44111,20 @@
}
}
},
+ "xlsx": {
+ "version": "0.18.5",
+ "resolved": "https://registry.npmjs.org/xlsx/-/xlsx-0.18.5.tgz",
+ "integrity": "sha512-dmg3LCjBPHZnQp5/F/+nnTa+miPJxUXB6vtk42YjBBKayDNagxGEeIdWApkYPOf3Z3pm3k62Knjzp7lMeTEtFQ==",
+ "requires": {
+ "adler-32": "~1.3.0",
+ "cfb": "~1.2.1",
+ "codepage": "~1.15.0",
+ "crc-32": "~1.2.1",
+ "ssf": "~0.11.2",
+ "wmf": "~1.0.1",
+ "word": "~0.3.0"
+ }
+ },
"xml": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/xml/-/xml-1.0.1.tgz",
diff --git a/packages/nocodb/package.json b/packages/nocodb/package.json
index d436b04bb1..147e41b876 100644
--- a/packages/nocodb/package.json
+++ b/packages/nocodb/package.json
@@ -186,7 +186,8 @@
"unique-names-generator": "^4.3.1",
"uuid": "^8.2.0",
"validator": "^13.1.1",
- "xc-core-ts": "^0.1.0"
+ "xc-core-ts": "^0.1.0",
+ "xlsx": "^0.18.5"
},
"devDependencies": {
"@bitjson/npm-scripts-info": "^1.0.0",
@@ -263,4 +264,4 @@
"**/*.spec.js"
]
}
-}
\ No newline at end of file
+}
diff --git a/packages/nocodb/src/lib/meta/api/dataApis/dataAliasExportApis.ts b/packages/nocodb/src/lib/meta/api/dataApis/dataAliasExportApis.ts
index 7e18477427..5c393ced04 100644
--- a/packages/nocodb/src/lib/meta/api/dataApis/dataAliasExportApis.ts
+++ b/packages/nocodb/src/lib/meta/api/dataApis/dataAliasExportApis.ts
@@ -1,12 +1,35 @@
import { Request, Response, Router } from 'express';
+import * as XLSX from 'xlsx';
import ncMetaAclMw from '../../helpers/ncMetaAclMw';
import {
extractCsvData,
+ extractXlsxData,
getViewAndModelFromRequestByAliasOrId,
} from './helpers';
import apiMetrics from '../../helpers/apiMetrics';
import View from '../../../models/View';
+async function excelDataExport(req: Request, res: Response) {
+ const {model, view} = await getViewAndModelFromRequestByAliasOrId(req);
+ let targetView = view;
+ if (!targetView) {
+ targetView = await View.getDefaultView(model.id);
+ }
+ const { offset, elapsed, data } = await extractXlsxData(targetView, req);
+ const wb = XLSX.utils.book_new();
+ XLSX.utils.book_append_sheet(wb, data, targetView.title);
+ const buf = XLSX.write(wb, { type: "base64", bookType: "xlsx" });
+ res.set({
+ 'Access-Control-Expose-Headers': 'nc-export-offset',
+ 'nc-export-offset': offset,
+ 'nc-export-elapsed-time': elapsed,
+ 'Content-Disposition': `attachment; filename="${encodeURI(
+ targetView.title
+ )}-export.xlsx"`,
+ });
+ res.end(buf);
+}
+
async function csvDataExport(req: Request, res: Response) {
const { model, view } = await getViewAndModelFromRequestByAliasOrId(req);
let targetView = view;
@@ -38,5 +61,15 @@ router.get(
apiMetrics,
ncMetaAclMw(csvDataExport, 'exportCsv')
);
+router.get(
+ '/api/v1/db/data/:orgs/:projectName/:tableName/export/excel',
+ apiMetrics,
+ ncMetaAclMw(excelDataExport, 'exportExcel')
+);
+router.get(
+ '/api/v1/db/data/:orgs/:projectName/:tableName/views/:viewName/export/excel',
+ apiMetrics,
+ ncMetaAclMw(excelDataExport, 'exportExcel')
+);
export default router;
diff --git a/packages/nocodb/src/lib/meta/api/dataApis/helpers.ts b/packages/nocodb/src/lib/meta/api/dataApis/helpers.ts
index 27d93d356e..968f062265 100644
--- a/packages/nocodb/src/lib/meta/api/dataApis/helpers.ts
+++ b/packages/nocodb/src/lib/meta/api/dataApis/helpers.ts
@@ -8,6 +8,7 @@ import NcConnectionMgrv2 from '../../../utils/common/NcConnectionMgrv2';
import { isSystemColumn, UITypes } from 'nocodb-sdk';
import { nocoExecute } from 'nc-help';
+import * as XLSX from 'xlsx';
import Column from '../../../models/Column';
import LookupColumn from '../../../models/LookupColumn';
import LinkToAnotherRecordColumn from '../../../models/LinkToAnotherRecordColumn';
@@ -36,6 +37,32 @@ export async function getViewAndModelFromRequestByAliasOrId(
return { model, view };
}
+export async function extractXlsxData(view: View, req: Request) {
+ const base = await Base.get(view.base_id);
+
+ await view.getModelWithInfo();
+ await view.getColumns();
+
+ view.model.columns = view.columns
+ .filter((c) => c.show)
+ .map(
+ (c) =>
+ new Column({ ...c, ...view.model.columnsById[c.fk_column_id] } as any)
+ )
+ .filter((column) => !isSystemColumn(column) || view.show_system_fields);
+
+ const baseModel = await Model.getBaseModelSQL({
+ id: view.model.id,
+ viewId: view?.id,
+ dbDriver: NcConnectionMgrv2.get(base),
+ });
+
+ const { offset, dbRows, elapsed } = await getDbRows(baseModel, view, req);
+ const data = XLSX.utils.json_to_sheet(dbRows);
+
+ return { offset, dbRows, elapsed, data };
+}
+
export async function extractCsvData(view: View, req: Request) {
const base = await Base.get(view.base_id);
@@ -56,11 +83,27 @@ export async function extractCsvData(view: View, req: Request) {
dbDriver: NcConnectionMgrv2.get(base),
});
+ const { offset, dbRows, elapsed } = await getDbRows(baseModel, view, req);
+
+ const data = papaparse.unparse(
+ {
+ fields: view.model.columns.map((c) => c.title),
+ data: dbRows,
+ },
+ {
+ escapeFormulae: true,
+ }
+ );
+
+ return { offset, dbRows, elapsed, data };
+}
+
+async function getDbRows(baseModel, view: View, req: Request) {
let offset = +req.query.offset || 0;
const limit = 100;
// const size = +process.env.NC_EXPORT_MAX_SIZE || 1024;
const timeout = +process.env.NC_EXPORT_MAX_TIMEOUT || 5000;
- const csvRows = [];
+ const dbRows = [];
const startTime = process.hrtime();
let elapsed, temp;
@@ -89,30 +132,19 @@ export async function extractCsvData(view: View, req: Request) {
}
for (const row of rows) {
- const csvRow = { ...row };
+ const dbRow = { ...row };
for (const column of view.model.columns) {
if (isSystemColumn(column) && !view.show_system_fields) continue;
- csvRow[column.title] = await serializeCellValue({
+ dbRow[column.title] = await serializeCellValue({
value: row[column.title],
column,
});
}
- csvRows.push(csvRow);
+ dbRows.push(dbRow);
}
}
-
- const data = papaparse.unparse(
- {
- fields: view.model.columns.map((c) => c.title),
- data: csvRows,
- },
- {
- escapeFormulae: true,
- }
- );
-
- return { offset, csvRows, elapsed, data };
+ return { offset, dbRows, elapsed };
}
export async function serializeCellValue({
diff --git a/packages/nocodb/src/lib/meta/api/publicApis/publicDataExportApis.ts b/packages/nocodb/src/lib/meta/api/publicApis/publicDataExportApis.ts
index 49ecdf394a..f5ed20d574 100644
--- a/packages/nocodb/src/lib/meta/api/publicApis/publicDataExportApis.ts
+++ b/packages/nocodb/src/lib/meta/api/publicApis/publicDataExportApis.ts
@@ -1,4 +1,5 @@
import { Request, Response, Router } from 'express';
+import * as XLSX from 'xlsx';
import View from '../../../models/View';
import Model from '../../../models/Model';
import Base from '../../../models/Base';
@@ -12,8 +13,38 @@ import LookupColumn from '../../../models/LookupColumn';
import catchError, { NcError } from '../../helpers/catchError';
import getAst from '../../../db/sql-data-mapper/lib/sql/helpers/getAst';
+async function exportExcel(req: Request, res: Response) {
+ const view = await View.getByUUID(req.params.publicDataUuid);
+ if (!view) NcError.notFound('Not found');
+ if (view.type !== ViewTypes.GRID) NcError.notFound('Not found');
+
+ if (view.password && view.password !== req.headers?.['xc-password']) {
+ NcError.forbidden(ErrorMessages.INVALID_SHARED_VIEW_PASSWORD);
+ }
+
+ const model = await view.getModelWithInfo();
+ await view.getColumns();
+
+ const { offset, dbRows, elapsed } = await getDbRows(model, view, req);
+
+ const data = XLSX.utils.json_to_sheet(dbRows);
+ const wb = XLSX.utils.book_new();
+ XLSX.utils.book_append_sheet(wb, data, view.title);
+ const buf = XLSX.write(wb, { type: "base64", bookType: "xlsx" });
+ res.set({
+ 'Access-Control-Expose-Headers': 'nc-export-offset',
+ 'nc-export-offset': offset,
+ 'nc-export-elapsed-time': elapsed,
+ 'Content-Disposition': `attachment; filename="${encodeURI(
+ view.title
+ )}-export.xlsx"`,
+ });
+ res.end(buf);
+}
+
async function exportCsv(req: Request, res: Response) {
const view = await View.getByUUID(req.params.publicDataUuid);
+ const fields = req.query.fields;
if (!view) NcError.notFound('Not found');
if (view.type !== ViewTypes.GRID) NcError.notFound('Not found');
@@ -25,6 +56,40 @@ async function exportCsv(req: Request, res: Response) {
const model = await view.getModelWithInfo();
await view.getColumns();
+ const { offset, dbRows, elapsed } = await getDbRows(model, view, req);
+
+ const data = papaparse.unparse(
+ {
+ fields: model.columns
+ .sort((c1, c2) =>
+ Array.isArray(fields)
+ ? fields.indexOf(c1.title as any) - fields.indexOf(c2.title as any)
+ : 0
+ )
+ .filter(
+ (c) =>
+ !fields || !Array.isArray(fields) || fields.includes(c.title as any)
+ )
+ .map((c) => c.title),
+ data: dbRows,
+ },
+ {
+ escapeFormulae: true,
+ }
+ );
+
+ res.set({
+ 'Access-Control-Expose-Headers': 'nc-export-offset',
+ 'nc-export-offset': offset,
+ 'nc-export-elapsed-time': elapsed,
+ 'Content-Disposition': `attachment; filename="${encodeURI(
+ view.title
+ )}-export.csv"`,
+ });
+ res.send(data);
+}
+
+async function getDbRows(model, view: View, req: Request) {
view.model.columns = view.columns
.filter((c) => c.show)
.map(
@@ -35,7 +100,6 @@ async function exportCsv(req: Request, res: Response) {
if (!model) NcError.notFound('Table not found');
- const fields = req.query.fields;
const listArgs: any = { ...req.query };
try {
listArgs.filterArr = JSON.parse(listArgs.filterArrJson);
@@ -62,7 +126,7 @@ async function exportCsv(req: Request, res: Response) {
const limit = 100;
// const size = +process.env.NC_EXPORT_MAX_SIZE || 1024;
const timeout = +process.env.NC_EXPORT_MAX_TIMEOUT || 5000;
- const csvRows = [];
+ const dbRows = [];
const startTime = process.hrtime();
let elapsed, temp;
@@ -86,47 +150,18 @@ async function exportCsv(req: Request, res: Response) {
}
for (const row of rows) {
- const csvRow = { ...row };
+ const dbRow = { ...row };
for (const column of view.model.columns) {
- csvRow[column.title] = await serializeCellValue({
+ dbRow[column.title] = await serializeCellValue({
value: row[column.title],
column,
});
}
- csvRows.push(csvRow);
+ dbRows.push(dbRow);
}
}
-
- const data = papaparse.unparse(
- {
- fields: model.columns
- .sort((c1, c2) =>
- Array.isArray(fields)
- ? fields.indexOf(c1.title as any) - fields.indexOf(c2.title as any)
- : 0
- )
- .filter(
- (c) =>
- !fields || !Array.isArray(fields) || fields.includes(c.title as any)
- )
- .map((c) => c.title),
- data: csvRows,
- },
- {
- escapeFormulae: true,
- }
- );
-
- res.set({
- 'Access-Control-Expose-Headers': 'nc-export-offset',
- 'nc-export-offset': offset,
- 'nc-export-elapsed-time': elapsed,
- 'Content-Disposition': `attachment; filename="${encodeURI(
- view.title
- )}-export.csv"`,
- });
- res.send(data);
+ return { offset, dbRows, elapsed };
}
async function serializeCellValue({
@@ -198,4 +233,8 @@ router.get(
'/api/v1/db/public/shared-view/:publicDataUuid/rows/export/csv',
catchError(exportCsv)
);
+router.get(
+ '/api/v1/db/public/shared-view/:publicDataUuid/rows/export/excel',
+ catchError(exportExcel)
+);
export default router;
diff --git a/packages/nocodb/src/lib/utils/projectAcl.ts b/packages/nocodb/src/lib/utils/projectAcl.ts
index ceb9fcd034..a3482a7137 100644
--- a/packages/nocodb/src/lib/utils/projectAcl.ts
+++ b/packages/nocodb/src/lib/utils/projectAcl.ts
@@ -27,6 +27,7 @@ export default {
dataGroupBy: true,
commentsCount: true,
exportCsv: true,
+ exportExcel: true,
viewList: true,
columnList: true,
@@ -142,6 +143,7 @@ export default {
// project
projectGet: true,
exportCsv: true,
+ exportExcel: true,
//table
tableGet: true,
@@ -205,6 +207,7 @@ export default {
dataGroupBy: true,
commentsCount: true,
exportCsv: true,
+ exportExcel: true,
// sort & filter
sortList: true,
diff --git a/scripts/cypress/integration/spec/roleValidation.spec.js b/scripts/cypress/integration/spec/roleValidation.spec.js
index f9156c7a9f..a54aacc181 100644
--- a/scripts/cypress/integration/spec/roleValidation.spec.js
+++ b/scripts/cypress/integration/spec/roleValidation.spec.js
@@ -217,7 +217,7 @@ export function _viewMenu(roleType, previewMode, navDrawListCnt) {
// let navDrawListCnt = 2;
// Download CSV
- let actionsMenuItemsCnt = 1;
+ let actionsMenuItemsCnt = 2;
cy.openTableTab(columnName, 25);
@@ -234,10 +234,10 @@ export function _viewMenu(roleType, previewMode, navDrawListCnt) {
if (roleType == "owner" || roleType == "creator") {
navDrawListCnt = 3;
// Download CSV / Upload CSV / Shared View List / Webhook
- actionsMenuItemsCnt = 4;
+ actionsMenuItemsCnt = 5;
} else if (roleType == "editor") {
// Download CSV / Upload CSV
- actionsMenuItemsCnt = 2;
+ actionsMenuItemsCnt = 3;
}
cy.get(".v-navigation-drawer__content")
diff --git a/scripts/cypress/support/page_objects/mainPage.js b/scripts/cypress/support/page_objects/mainPage.js
index b8d321561b..b388264871 100644
--- a/scripts/cypress/support/page_objects/mainPage.js
+++ b/scripts/cypress/support/page_objects/mainPage.js
@@ -251,22 +251,27 @@ export class _mainPage {
shareViewList = () => {
cy.get(".nc-actions-menu-btn").click();
- return cy.getActiveMenu().find('[role="menuitem"]').eq(2);
+ return cy.getActiveMenu().find('[role="menuitem"]').contains("Shared View List");
};
downloadCsv = () => {
cy.get(".nc-actions-menu-btn").click();
- return cy.getActiveMenu().find('[role="menuitem"]').eq(0);
+ return cy.getActiveMenu().find('[role="menuitem"]').contains("Download as CSV");
+ };
+
+ downloadExcel = () => {
+ cy.get(".nc-actions-menu-btn").click();
+ return cy.getActiveMenu().find('[role="menuitem"]').contains("Download as XLSX");
};
uploadCsv = () => {
cy.get(".nc-actions-menu-btn").click();
- return cy.getActiveMenu().find('[role="menuitem"]').eq(1);
+ return cy.getActiveMenu().find('[role="menuitem"]').contains("Upload CSV");
};
automations = () => {
cy.get(".nc-actions-menu-btn").click();
- return cy.getActiveMenu().find('[role="menuitem"]').eq(3);
+ return cy.getActiveMenu().find('[role="menuitem"]').contains("Webhooks");
};
hideField = (field) => {