diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index 26e7f9a5e..59795d5f8 100644 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -16,7 +16,6 @@ specific language governing permissions and limitations under the License. --> - # CODE OF CONDUCT *The following is copied for your convenience from . If there's a discrepancy between the two, let us know or submit a PR to fix it.* diff --git a/superset-frontend/package-lock.json b/superset-frontend/package-lock.json index ee61ed7ca..6316286ab 100644 --- a/superset-frontend/package-lock.json +++ b/superset-frontend/package-lock.json @@ -67,7 +67,6 @@ "core-js": "^3.37.1", "d3-scale": "^2.1.2", "dom-to-image-more": "^3.2.0", - "dom-to-pdf": "^0.3.1", "emotion-rgba": "0.0.12", "fast-glob": "^3.2.7", "fs-extra": "^10.0.0", @@ -16065,11 +16064,6 @@ "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz", "integrity": "sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw==" }, - "node_modules/@types/raf": { - "version": "3.4.2", - "resolved": "https://registry.npmjs.org/@types/raf/-/raf-3.4.2.tgz", - "integrity": "sha512-sM4HyDVlDFl4goOXPF+g9nNHJFZQGot+HgySjM4cRjqXzjdatcEvYrtG4Ia8XumR9T6k8G2tW9B7hnUj51Uf0A==" - }, "node_modules/@types/range-parser": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.4.tgz", @@ -19800,6 +19794,7 @@ "version": "2.1.2", "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==", + "dev": true, "bin": { "atob": "bin/atob.js" }, @@ -20651,14 +20646,6 @@ "resolved": "https://registry.npmjs.org/base16/-/base16-1.0.0.tgz", "integrity": "sha512-pNdYkNPiJUnEhnfXV56+sQy8+AaPcG3POZAUnwr4EeqCUZFz4u2PePbo3e5Gj4ziYPCWGUZT9RHisvJKnwFuBQ==" }, - "node_modules/base64-arraybuffer": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-1.0.2.tgz", - "integrity": "sha512-I3yl4r9QB5ZRY3XuJVEPfc2XhZO6YweFPI+UovAzn+8/hb3oJ6lnysaFcjVpkCPfVWFUDvoZ8kmVDP7WyRtYtQ==", - "engines": { - "node": ">= 0.6.0" - } - }, "node_modules/base64-js": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", @@ -21093,17 +21080,6 @@ "node-int64": "^0.4.0" } }, - "node_modules/btoa": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/btoa/-/btoa-1.2.1.tgz", - "integrity": "sha512-SB4/MIGlsiVkMcHmT+pSmIPoNDoHg+7cMzmt3Uxt628MTz2487DKSqK/fuhFBrkuqrYv5UCEnACpF4dTFNKc/g==", - "bin": { - "btoa": "bin/btoa.js" - }, - "engines": { - "node": ">= 0.4.0" - } - }, "node_modules/buf-compare": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/buf-compare/-/buf-compare-1.0.1.tgz", @@ -21663,29 +21639,6 @@ } ] }, - "node_modules/canvg": { - "version": "3.0.10", - "resolved": "https://registry.npmjs.org/canvg/-/canvg-3.0.10.tgz", - "integrity": "sha512-qwR2FRNO9NlzTeKIPIKpnTY6fqwuYSequ8Ru8c0YkYU7U0oW+hLUvWadLvAu1Rl72OMNiFhoLu4f8eUjQ7l/+Q==", - "dependencies": { - "@babel/runtime": "^7.12.5", - "@types/raf": "^3.4.0", - "core-js": "^3.8.3", - "raf": "^3.4.1", - "regenerator-runtime": "^0.13.7", - "rgbcolor": "^1.0.1", - "stackblur-canvas": "^2.0.0", - "svg-pathdata": "^6.0.3" - }, - "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/canvg/node_modules/regenerator-runtime": { - "version": "0.13.11", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", - "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==" - }, "node_modules/capture-exit": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/capture-exit/-/capture-exit-2.0.0.tgz", @@ -23523,14 +23476,6 @@ "isobject": "^3.0.1" } }, - "node_modules/css-line-break": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/css-line-break/-/css-line-break-2.1.0.tgz", - "integrity": "sha512-FHcKFCZcAha3LwfVBhCQbW2nCNbkZXn7KVUJcsT5/P8YmfsVja0FMPJr0B903j/E69HUphKiV9iQArX8SDYA4w==", - "dependencies": { - "utrie": "^1.0.2" - } - }, "node_modules/css-loader": { "version": "6.8.1", "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-6.8.1.tgz", @@ -25652,25 +25597,11 @@ "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" } }, - "node_modules/dom-to-image": { - "version": "2.6.0", - "resolved": "git+ssh://git@github.com/dmapper/dom-to-image.git#a7c386a8ea813930f05449ac71ab4be0c262dff3", - "license": "MIT" - }, "node_modules/dom-to-image-more": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/dom-to-image-more/-/dom-to-image-more-3.2.0.tgz", "integrity": "sha512-2bGQTB6m17MBseVhIjShwZqqqCyVS9GgTykWqvVXMqr56fSgHhXnEvZfZkaSuHJYW3ICZQ3sZwAu+UY5tfsF9Q==" }, - "node_modules/dom-to-pdf": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/dom-to-pdf/-/dom-to-pdf-0.3.2.tgz", - "integrity": "sha512-eHLQ/IK+2PQlRjybQ9UHYwpiTd/YZFKqGFyRCjVvi6CPlH58drWQnxf7HBCVRUyAjOtI3RG0kvLidPhC7dOhcQ==", - "dependencies": { - "dom-to-image": "git+https://github.com/dmapper/dom-to-image.git", - "jspdf": "^2.5.1" - } - }, "node_modules/dom-walk": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/dom-walk/-/dom-walk-0.1.1.tgz", @@ -25701,12 +25632,6 @@ "url": "https://github.com/fb55/domhandler?sponsor=1" } }, - "node_modules/dompurify": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-2.3.3.tgz", - "integrity": "sha512-dqnqRkPMAjOZE0FogZ+ceJNM2dZ3V/yNOuFB7+39qpO93hHhfRpHw3heYQC7DPK9FqbQTfBKUJhiSfz4MvXYwg==", - "optional": true - }, "node_modules/domutils": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.1.0.tgz", @@ -28672,11 +28597,6 @@ "resolved": "https://registry.npmjs.org/fetch-retry/-/fetch-retry-6.0.0.tgz", "integrity": "sha512-BUFj1aMubgib37I3v4q78fYo63Po7t4HUPTpQ6/QE6yK6cIQrP+W43FYToeTEyg5m2Y7eFUtijUuAv/PDlWuag==" }, - "node_modules/fflate": { - "version": "0.4.8", - "resolved": "https://registry.npmjs.org/fflate/-/fflate-0.4.8.tgz", - "integrity": "sha512-FJqqoDBR00Mdj9ppamLa/Y7vxm+PRmNWA67N846RvsoYVMKB4q3y/de5PA7gUmRMYK/8CMz2GDZQmCRN1wBcWA==" - }, "node_modules/figures": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", @@ -32618,18 +32538,6 @@ "node": ">=6" } }, - "node_modules/html2canvas": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/html2canvas/-/html2canvas-1.4.1.tgz", - "integrity": "sha512-fPU6BHNpsyIhr8yyMpTLLxAbkaK8ArIBcmZIRiBLiDhjeqvXolaEmDGmELFuX9I4xDcaKKcJl+TKZLqruBbmWA==", - "dependencies": { - "css-line-break": "^2.1.0", - "text-segmentation": "^1.0.3" - }, - "engines": { - "node": ">=8.0.0" - } - }, "node_modules/htmlparser2": { "version": "8.0.2", "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-8.0.2.tgz", @@ -39492,23 +39400,6 @@ "node": "*" } }, - "node_modules/jspdf": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/jspdf/-/jspdf-2.5.1.tgz", - "integrity": "sha512-hXObxz7ZqoyhxET78+XR34Xu2qFGrJJ2I2bE5w4SM8eFaFEkW2xcGRVUss360fYelwRSid/jT078kbNvmoW0QA==", - "dependencies": { - "@babel/runtime": "^7.14.0", - "atob": "^2.1.2", - "btoa": "^1.2.1", - "canvg": "^3.0.6", - "fflate": "^0.4.8", - "html2canvas": "^1.0.0-rc.5" - }, - "optionalDependencies": { - "core-js": "^3.6.0", - "dompurify": "^2.2.0" - } - }, "node_modules/jsprim": { "version": "1.4.2", "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.2.tgz", @@ -56514,14 +56405,6 @@ "integrity": "sha512-r5a3l5HzYlIC68TpmYKlxWjmOP6wiPJ1vWv2HeLhNsRZMrCkxeqxiHlQ21oXmQ4F3SiryXBHhAD7JZqvOJjFmg==", "dev": true }, - "node_modules/rgbcolor": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/rgbcolor/-/rgbcolor-1.0.1.tgz", - "integrity": "sha512-9aZLIrhRaD97sgVhtJOW6ckOEh6/GnvQtdVNfdZ6s67+3/XwLS9lBcQYzEEhYVeUowN7pRzMLsyGhK2i/xvWbw==", - "engines": { - "node": ">= 0.8.15" - } - }, "node_modules/rimraf": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", @@ -58073,14 +57956,6 @@ "node": ">=8" } }, - "node_modules/stackblur-canvas": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/stackblur-canvas/-/stackblur-canvas-2.6.0.tgz", - "integrity": "sha512-8S1aIA+UoF6erJYnglGPug6MaHYGo1Ot7h5fuXx4fUPvcvQfcdw2o/ppCse63+eZf8PPidSu4v1JnmEVtEDnpg==", - "engines": { - "node": ">=0.1.14" - } - }, "node_modules/static-eval": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/static-eval/-/static-eval-2.1.0.tgz", @@ -58744,14 +58619,6 @@ "integrity": "sha512-e4hG1hRwoOdRb37cIMSgzNsxyzKfayW6VOflrwvR+/bzrkyxY/31WkbgnQpgtrNp1SdpJvpUAGTa/ZoiPNDuRQ==", "dev": true }, - "node_modules/svg-pathdata": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/svg-pathdata/-/svg-pathdata-6.0.3.tgz", - "integrity": "sha512-qsjeeq5YjBZ5eMdFuUa4ZosMLxgr5RZ+F+Y1OrDhuOCEInRMA3x74XdBtggJcj9kOeInz0WE+LgCPDkZFlBYJw==", - "engines": { - "node": ">=12.0.0" - } - }, "node_modules/svgo": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/svgo/-/svgo-3.2.0.tgz", @@ -59189,14 +59056,6 @@ "node": ">=0.10" } }, - "node_modules/text-segmentation": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/text-segmentation/-/text-segmentation-1.0.3.tgz", - "integrity": "sha512-iOiPUo/BGnZ6+54OsWxZidGCsdU8YbE4PSpdPinp7DeMtUJNJBoJ/ouUSTJjHkh1KntHaltHl/gDs2FC4i5+Nw==", - "dependencies": { - "utrie": "^1.0.2" - } - }, "node_modules/text-table": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", @@ -60627,14 +60486,6 @@ "node": ">= 0.4.0" } }, - "node_modules/utrie": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/utrie/-/utrie-1.0.2.tgz", - "integrity": "sha512-1MLa5ouZiOmQzUbjbu9VmjLzn1QLXBhwpUa7kdLUQK+KQ5KA9I1vk5U4YHe/X2Ch7PYnJfWuWT+VbuxbGwljhw==", - "dependencies": { - "base64-arraybuffer": "^1.0.2" - } - }, "node_modules/uuid": { "version": "3.4.0", "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", @@ -81093,11 +80944,6 @@ "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz", "integrity": "sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw==" }, - "@types/raf": { - "version": "3.4.2", - "resolved": "https://registry.npmjs.org/@types/raf/-/raf-3.4.2.tgz", - "integrity": "sha512-sM4HyDVlDFl4goOXPF+g9nNHJFZQGot+HgySjM4cRjqXzjdatcEvYrtG4Ia8XumR9T6k8G2tW9B7hnUj51Uf0A==" - }, "@types/range-parser": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.4.tgz", @@ -84053,7 +83899,8 @@ "atob": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", - "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==" + "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==", + "dev": true }, "atomic-sleep": { "version": "1.0.0", @@ -84715,11 +84562,6 @@ "resolved": "https://registry.npmjs.org/base16/-/base16-1.0.0.tgz", "integrity": "sha512-pNdYkNPiJUnEhnfXV56+sQy8+AaPcG3POZAUnwr4EeqCUZFz4u2PePbo3e5Gj4ziYPCWGUZT9RHisvJKnwFuBQ==" }, - "base64-arraybuffer": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-1.0.2.tgz", - "integrity": "sha512-I3yl4r9QB5ZRY3XuJVEPfc2XhZO6YweFPI+UovAzn+8/hb3oJ6lnysaFcjVpkCPfVWFUDvoZ8kmVDP7WyRtYtQ==" - }, "base64-js": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", @@ -85058,11 +84900,6 @@ "node-int64": "^0.4.0" } }, - "btoa": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/btoa/-/btoa-1.2.1.tgz", - "integrity": "sha512-SB4/MIGlsiVkMcHmT+pSmIPoNDoHg+7cMzmt3Uxt628MTz2487DKSqK/fuhFBrkuqrYv5UCEnACpF4dTFNKc/g==" - }, "buf-compare": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/buf-compare/-/buf-compare-1.0.1.tgz", @@ -85446,28 +85283,6 @@ "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001639.tgz", "integrity": "sha512-eFHflNTBIlFwP2AIKaYuBQN/apnUoKNhBdza8ZnW/h2di4LCZ4xFqYlxUxo+LQ76KFI1PGcC1QDxMbxTZpSCAg==" }, - "canvg": { - "version": "3.0.10", - "resolved": "https://registry.npmjs.org/canvg/-/canvg-3.0.10.tgz", - "integrity": "sha512-qwR2FRNO9NlzTeKIPIKpnTY6fqwuYSequ8Ru8c0YkYU7U0oW+hLUvWadLvAu1Rl72OMNiFhoLu4f8eUjQ7l/+Q==", - "requires": { - "@babel/runtime": "^7.12.5", - "@types/raf": "^3.4.0", - "core-js": "^3.8.3", - "raf": "^3.4.1", - "regenerator-runtime": "^0.13.7", - "rgbcolor": "^1.0.1", - "stackblur-canvas": "^2.0.0", - "svg-pathdata": "^6.0.3" - }, - "dependencies": { - "regenerator-runtime": { - "version": "0.13.11", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", - "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==" - } - } - }, "capture-exit": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/capture-exit/-/capture-exit-2.0.0.tgz", @@ -86877,14 +86692,6 @@ "isobject": "^3.0.1" } }, - "css-line-break": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/css-line-break/-/css-line-break-2.1.0.tgz", - "integrity": "sha512-FHcKFCZcAha3LwfVBhCQbW2nCNbkZXn7KVUJcsT5/P8YmfsVja0FMPJr0B903j/E69HUphKiV9iQArX8SDYA4w==", - "requires": { - "utrie": "^1.0.2" - } - }, "css-loader": { "version": "6.8.1", "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-6.8.1.tgz", @@ -88526,24 +88333,11 @@ "entities": "^4.2.0" } }, - "dom-to-image": { - "version": "git+ssh://git@github.com/dmapper/dom-to-image.git#a7c386a8ea813930f05449ac71ab4be0c262dff3", - "from": "dom-to-image@git+https://github.com/dmapper/dom-to-image.git" - }, "dom-to-image-more": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/dom-to-image-more/-/dom-to-image-more-3.2.0.tgz", "integrity": "sha512-2bGQTB6m17MBseVhIjShwZqqqCyVS9GgTykWqvVXMqr56fSgHhXnEvZfZkaSuHJYW3ICZQ3sZwAu+UY5tfsF9Q==" }, - "dom-to-pdf": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/dom-to-pdf/-/dom-to-pdf-0.3.2.tgz", - "integrity": "sha512-eHLQ/IK+2PQlRjybQ9UHYwpiTd/YZFKqGFyRCjVvi6CPlH58drWQnxf7HBCVRUyAjOtI3RG0kvLidPhC7dOhcQ==", - "requires": { - "dom-to-image": "git+https://github.com/dmapper/dom-to-image.git", - "jspdf": "^2.5.1" - } - }, "dom-walk": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/dom-walk/-/dom-walk-0.1.1.tgz", @@ -88562,12 +88356,6 @@ "domelementtype": "^2.3.0" } }, - "dompurify": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-2.3.3.tgz", - "integrity": "sha512-dqnqRkPMAjOZE0FogZ+ceJNM2dZ3V/yNOuFB7+39qpO93hHhfRpHw3heYQC7DPK9FqbQTfBKUJhiSfz4MvXYwg==", - "optional": true - }, "domutils": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.1.0.tgz", @@ -90854,11 +90642,6 @@ "resolved": "https://registry.npmjs.org/fetch-retry/-/fetch-retry-6.0.0.tgz", "integrity": "sha512-BUFj1aMubgib37I3v4q78fYo63Po7t4HUPTpQ6/QE6yK6cIQrP+W43FYToeTEyg5m2Y7eFUtijUuAv/PDlWuag==" }, - "fflate": { - "version": "0.4.8", - "resolved": "https://registry.npmjs.org/fflate/-/fflate-0.4.8.tgz", - "integrity": "sha512-FJqqoDBR00Mdj9ppamLa/Y7vxm+PRmNWA67N846RvsoYVMKB4q3y/de5PA7gUmRMYK/8CMz2GDZQmCRN1wBcWA==" - }, "figures": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", @@ -93759,15 +93542,6 @@ } } }, - "html2canvas": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/html2canvas/-/html2canvas-1.4.1.tgz", - "integrity": "sha512-fPU6BHNpsyIhr8yyMpTLLxAbkaK8ArIBcmZIRiBLiDhjeqvXolaEmDGmELFuX9I4xDcaKKcJl+TKZLqruBbmWA==", - "requires": { - "css-line-break": "^2.1.0", - "text-segmentation": "^1.0.3" - } - }, "htmlparser2": { "version": "8.0.2", "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-8.0.2.tgz", @@ -98769,21 +98543,6 @@ "through": ">=2.2.7 <3" } }, - "jspdf": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/jspdf/-/jspdf-2.5.1.tgz", - "integrity": "sha512-hXObxz7ZqoyhxET78+XR34Xu2qFGrJJ2I2bE5w4SM8eFaFEkW2xcGRVUss360fYelwRSid/jT078kbNvmoW0QA==", - "requires": { - "@babel/runtime": "^7.14.0", - "atob": "^2.1.2", - "btoa": "^1.2.1", - "canvg": "^3.0.6", - "core-js": "^3.6.0", - "dompurify": "^2.2.0", - "fflate": "^0.4.8", - "html2canvas": "^1.0.0-rc.5" - } - }, "jsprim": { "version": "1.4.2", "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.2.tgz", @@ -110459,11 +110218,6 @@ "integrity": "sha512-r5a3l5HzYlIC68TpmYKlxWjmOP6wiPJ1vWv2HeLhNsRZMrCkxeqxiHlQ21oXmQ4F3SiryXBHhAD7JZqvOJjFmg==", "dev": true }, - "rgbcolor": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/rgbcolor/-/rgbcolor-1.0.1.tgz", - "integrity": "sha512-9aZLIrhRaD97sgVhtJOW6ckOEh6/GnvQtdVNfdZ6s67+3/XwLS9lBcQYzEEhYVeUowN7pRzMLsyGhK2i/xvWbw==" - }, "rimraf": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", @@ -111693,11 +111447,6 @@ } } }, - "stackblur-canvas": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/stackblur-canvas/-/stackblur-canvas-2.6.0.tgz", - "integrity": "sha512-8S1aIA+UoF6erJYnglGPug6MaHYGo1Ot7h5fuXx4fUPvcvQfcdw2o/ppCse63+eZf8PPidSu4v1JnmEVtEDnpg==" - }, "static-eval": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/static-eval/-/static-eval-2.1.0.tgz", @@ -112189,11 +111938,6 @@ "integrity": "sha512-e4hG1hRwoOdRb37cIMSgzNsxyzKfayW6VOflrwvR+/bzrkyxY/31WkbgnQpgtrNp1SdpJvpUAGTa/ZoiPNDuRQ==", "dev": true }, - "svg-pathdata": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/svg-pathdata/-/svg-pathdata-6.0.3.tgz", - "integrity": "sha512-qsjeeq5YjBZ5eMdFuUa4ZosMLxgr5RZ+F+Y1OrDhuOCEInRMA3x74XdBtggJcj9kOeInz0WE+LgCPDkZFlBYJw==" - }, "svgo": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/svgo/-/svgo-3.2.0.tgz", @@ -112515,14 +112259,6 @@ "integrity": "sha512-wiBrwC1EhBelW12Zy26JeOUkQ5mRu+5o8rpsJk5+2t+Y5vE7e842qtZDQ2g1NpX/29HdyFeJ4nSIhI47ENSxlQ==", "dev": true }, - "text-segmentation": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/text-segmentation/-/text-segmentation-1.0.3.tgz", - "integrity": "sha512-iOiPUo/BGnZ6+54OsWxZidGCsdU8YbE4PSpdPinp7DeMtUJNJBoJ/ouUSTJjHkh1KntHaltHl/gDs2FC4i5+Nw==", - "requires": { - "utrie": "^1.0.2" - } - }, "text-table": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", @@ -113569,14 +113305,6 @@ "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=", "dev": true }, - "utrie": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/utrie/-/utrie-1.0.2.tgz", - "integrity": "sha512-1MLa5ouZiOmQzUbjbu9VmjLzn1QLXBhwpUa7kdLUQK+KQ5KA9I1vk5U4YHe/X2Ch7PYnJfWuWT+VbuxbGwljhw==", - "requires": { - "base64-arraybuffer": "^1.0.2" - } - }, "uuid": { "version": "3.4.0", "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", diff --git a/superset-frontend/package.json b/superset-frontend/package.json index aec0ea6b8..bb7a2face 100644 --- a/superset-frontend/package.json +++ b/superset-frontend/package.json @@ -132,7 +132,6 @@ "core-js": "^3.37.1", "d3-scale": "^2.1.2", "dom-to-image-more": "^3.2.0", - "dom-to-pdf": "^0.3.1", "emotion-rgba": "0.0.12", "fast-glob": "^3.2.7", "fs-extra": "^10.0.0", diff --git a/superset-frontend/src/dashboard/components/Header/HeaderActionsDropdown/index.jsx b/superset-frontend/src/dashboard/components/Header/HeaderActionsDropdown/index.jsx index 73d136e81..50cdb6781 100644 --- a/superset-frontend/src/dashboard/components/Header/HeaderActionsDropdown/index.jsx +++ b/superset-frontend/src/dashboard/components/Header/HeaderActionsDropdown/index.jsx @@ -276,7 +276,7 @@ export class HeaderActionsDropdown extends PureComponent { pdfMenuItemTitle={t('Export to PDF')} imageMenuItemTitle={t('Download as Image')} dashboardTitle={dashboardTitle} - addDangerToast={addDangerToast} + dashboardId={dashboardId} /> {userCanShare && ( diff --git a/superset-frontend/src/dashboard/components/menu/DownloadMenuItems/DownloadAsPdf.test.tsx b/superset-frontend/src/dashboard/components/menu/DownloadMenuItems/DownloadAsPdf.test.tsx deleted file mode 100644 index a799ffbce..000000000 --- a/superset-frontend/src/dashboard/components/menu/DownloadMenuItems/DownloadAsPdf.test.tsx +++ /dev/null @@ -1,66 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -import { SyntheticEvent } from 'react'; -import { render, screen, waitFor } from 'spec/helpers/testing-library'; -import userEvent from '@testing-library/user-event'; -import { Menu } from 'src/components/Menu'; -import downloadAsPdf from 'src/utils/downloadAsPdf'; -import DownloadAsPdf from './DownloadAsPdf'; - -jest.mock('src/utils/downloadAsPdf', () => ({ - __esModule: true, - default: jest.fn(() => (_e: SyntheticEvent) => {}), -})); - -const createProps = () => ({ - addDangerToast: jest.fn(), - text: 'Export as PDF', - dashboardTitle: 'Test Dashboard', - logEvent: jest.fn(), -}); - -const renderComponent = () => { - render( - - - , - ); -}; - -test('Should call download pdf on click', async () => { - const props = createProps(); - renderComponent(); - await waitFor(() => { - expect(downloadAsPdf).toBeCalledTimes(0); - expect(props.addDangerToast).toBeCalledTimes(0); - }); - - userEvent.click(screen.getByRole('button', { name: 'Export as PDF' })); - - await waitFor(() => { - expect(downloadAsPdf).toBeCalledTimes(1); - expect(props.addDangerToast).toBeCalledTimes(0); - }); -}); - -test('Component is rendered with role="button"', async () => { - renderComponent(); - const button = screen.getByRole('button', { name: 'Export as PDF' }); - expect(button).toBeInTheDocument(); -}); diff --git a/superset-frontend/src/dashboard/components/menu/DownloadMenuItems/DownloadAsPdf.tsx b/superset-frontend/src/dashboard/components/menu/DownloadMenuItems/DownloadAsPdf.tsx deleted file mode 100644 index 4f3566728..000000000 --- a/superset-frontend/src/dashboard/components/menu/DownloadMenuItems/DownloadAsPdf.tsx +++ /dev/null @@ -1,55 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -import { SyntheticEvent } from 'react'; -import { logging, t } from '@superset-ui/core'; -import { Menu } from 'src/components/Menu'; -import downloadAsPdf from 'src/utils/downloadAsPdf'; -import { LOG_ACTIONS_DASHBOARD_DOWNLOAD_AS_PDF } from 'src/logger/LogUtils'; - -export default function DownloadAsPdf({ - text, - logEvent, - dashboardTitle, - addDangerToast, - ...rest -}: { - text: string; - addDangerToast: Function; - dashboardTitle: string; - logEvent?: Function; -}) { - const SCREENSHOT_NODE_SELECTOR = '.dashboard'; - const onDownloadPdf = async (e: SyntheticEvent) => { - try { - downloadAsPdf(SCREENSHOT_NODE_SELECTOR, dashboardTitle, true)(e); - } catch (error) { - logging.error(error); - addDangerToast(t('Sorry, something went wrong. Try again later.')); - } - logEvent?.(LOG_ACTIONS_DASHBOARD_DOWNLOAD_AS_PDF); - }; - - return ( - -
- {text} -
-
- ); -} diff --git a/superset-frontend/src/dashboard/components/menu/DownloadMenuItems/DownloadMenuItems.test.tsx b/superset-frontend/src/dashboard/components/menu/DownloadMenuItems/DownloadMenuItems.test.tsx index a4e058572..fe453bb39 100644 --- a/superset-frontend/src/dashboard/components/menu/DownloadMenuItems/DownloadMenuItems.test.tsx +++ b/superset-frontend/src/dashboard/components/menu/DownloadMenuItems/DownloadMenuItems.test.tsx @@ -20,15 +20,17 @@ import { render, screen } from 'spec/helpers/testing-library'; import DownloadMenuItems from '.'; const createProps = () => ({ - addDangerToast: jest.fn(), pdfMenuItemTitle: 'Export to PDF', imageMenuItemTitle: 'Download as Image', dashboardTitle: 'Test Dashboard', logEvent: jest.fn(), + dashboardId: '123', }); const renderComponent = () => { - render(); + render(, { + useRedux: true, + }); }; test('Should render menu items', () => { diff --git a/superset-frontend/src/dashboard/components/menu/DownloadMenuItems/DownloadScreenshot.test.tsx b/superset-frontend/src/dashboard/components/menu/DownloadMenuItems/DownloadScreenshot.test.tsx new file mode 100644 index 000000000..21bd7022e --- /dev/null +++ b/superset-frontend/src/dashboard/components/menu/DownloadMenuItems/DownloadScreenshot.test.tsx @@ -0,0 +1,198 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { render, screen, waitFor } from 'spec/helpers/testing-library'; +import userEvent from '@testing-library/user-event'; +import { Menu } from 'src/components/Menu'; +import fetchMock from 'fetch-mock'; +import { logging } from '@superset-ui/core'; +import { DownloadScreenshotFormat } from './types'; +import DownloadScreenshot from './DownloadScreenshot'; + +const mockAddDangerToast = jest.fn(); +const mockLogEvent = jest.fn(); +const mockAddSuccessToast = jest.fn(); +const mockAddInfoToast = jest.fn(); + +jest.spyOn(logging, 'error').mockImplementation(() => {}); + +jest.mock('src/components/MessageToasts/withToasts', () => ({ + useToasts: () => ({ + addDangerToast: mockAddDangerToast, + addSuccessToast: mockAddSuccessToast, + addInfoToast: mockAddInfoToast, + }), +})); + +const defaultProps = () => ({ + text: 'Download', + dashboardId: '123', + format: DownloadScreenshotFormat.PDF, + logEvent: mockLogEvent, +}); + +const renderComponent = () => { + render( + + + , + { + useRedux: true, + }, + ); +}; + +describe('DownloadScreenshot component', () => { + beforeEach(() => { + jest.clearAllMocks(); + jest.useRealTimers(); + fetchMock.restore(); + }); + + afterAll(() => { + jest.restoreAllMocks(); + }); + + test('renders correctly with the given text', () => { + renderComponent(); + expect(screen.getByText('Download')).toBeInTheDocument(); + }); + + test('button renders with role="button"', async () => { + renderComponent(); + const button = screen.getByRole('button', { name: 'Download' }); + expect(button).toBeInTheDocument(); + }); + + test('displays error message when API call fails', async () => { + const props = defaultProps(); + + fetchMock.post( + `glob:*/api/v1/dashboard/${props.dashboardId}/cache_dashboard_screenshot`, + { + status: 400, + body: {}, + }, + ); + + renderComponent(); + + userEvent.click(screen.getByRole('button', { name: 'Download' })); + + await waitFor(() => { + expect(mockAddDangerToast).toHaveBeenCalledWith( + 'The screenshot could not be downloaded. Please, try again later.', + ); + }); + }); + + test('displays success message when API call succeeds', async () => { + const props = defaultProps(); + fetchMock.post( + `glob:*/api/v1/dashboard/${props.dashboardId}/cache_dashboard_screenshot`, + { + status: 200, + body: { + image_url: 'mocked_image_url', + }, + }, + ); + + fetchMock.get('glob:*/mocked_image_url?download_format=pdf', { + status: 200, + body: {}, + }); + + renderComponent(); + + userEvent.click(screen.getByRole('button', { name: 'Download' })); + + await waitFor(() => { + expect(mockAddInfoToast).toHaveBeenCalledWith( + 'The screenshot is being generated. Please, do not leave the page.', + ); + }); + }); + + test('throws error when no image URL is provided', async () => { + const props = defaultProps(); + fetchMock.post( + `glob:*/api/v1/dashboard/${props.dashboardId}/cache_dashboard_screenshot`, + { + status: 200, + body: { + image_url: '', + }, + }, + ); + + renderComponent(); + + // Simulate the user clicking the download button + userEvent.click(screen.getByRole('button', { name: 'Download' })); + + await waitFor(() => { + expect(mockAddDangerToast).toHaveBeenCalledWith( + 'The screenshot could not be downloaded. Please, try again later.', + ); + }); + }); + + test('displays success message when image retrieval succeeds', async () => { + const props = defaultProps(); + const imageUrl = 'glob:*/mocked_image_url?download_format=pdf'; + fetchMock.post( + `glob:*/api/v1/dashboard/${props.dashboardId}/cache_dashboard_screenshot`, + { + status: 200, + body: { + image_url: 'mocked_image_url', + }, + }, + ); + + fetchMock.get(imageUrl, { + status: 200, + headers: { + 'Content-Type': 'image/png', + }, + body: new Blob([], { type: 'image/png' }), + }); + + global.URL.createObjectURL = jest.fn(() => 'mockedObjectURL'); + global.URL.revokeObjectURL = jest.fn(); + + // Render the component + renderComponent(); + + // Simulate the user clicking the download button + userEvent.click(screen.getByRole('button', { name: 'Download' })); + + await waitFor(() => { + expect(fetchMock.calls(imageUrl).length).toBe(1); + }); + + // Wait for the successful image retrieval message + await waitFor(() => { + expect(mockAddSuccessToast).toHaveBeenCalledWith( + 'The screenshot is now being downloaded.', + ); + }); + }); +}); diff --git a/superset-frontend/src/dashboard/components/menu/DownloadMenuItems/DownloadScreenshot.tsx b/superset-frontend/src/dashboard/components/menu/DownloadMenuItems/DownloadScreenshot.tsx new file mode 100644 index 000000000..3410accd1 --- /dev/null +++ b/superset-frontend/src/dashboard/components/menu/DownloadMenuItems/DownloadScreenshot.tsx @@ -0,0 +1,145 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { logging, t, SupersetClient } from '@superset-ui/core'; +import { Menu } from 'src/components/Menu'; +import { + LOG_ACTIONS_DASHBOARD_DOWNLOAD_AS_IMAGE, + LOG_ACTIONS_DASHBOARD_DOWNLOAD_AS_PDF, +} from 'src/logger/LogUtils'; +import { RootState } from 'src/dashboard/types'; +import { useSelector } from 'react-redux'; +import { useToasts } from 'src/components/MessageToasts/withToasts'; +import { last } from 'lodash'; +import { DownloadScreenshotFormat } from './types'; + +const RETRY_INTERVAL = 3000; +const MAX_RETRIES = 30; + +export default function DownloadScreenshot({ + text, + logEvent, + dashboardId, + format, + ...rest +}: { + text: string; + dashboardId: string; + logEvent?: Function; + format: string; +}) { + const anchor = useSelector( + (state: RootState) => last(state.dashboardState.activeTabs) || undefined, + ); + const { addDangerToast, addSuccessToast, addInfoToast } = useToasts(); + + const onDownloadScreenshot = () => { + let retries = 0; + + // this function checks if the image is ready + const checkImageReady = (imageUrl: string) => + fetch(`${imageUrl}?download_format=${format}`) + .then(response => { + if (response.status === 404) { + throw new Error('Image not ready'); + } + return response.blob(); + }) + .then(blob => { + const url = window.URL.createObjectURL(blob); + const a = document.createElement('a'); + a.href = url; + a.download = `screenshot.${format}`; + document.body.appendChild(a); + a.click(); + document.body.removeChild(a); + window.URL.revokeObjectURL(url); + }); + + // this is the functions that handles the retries + const fetchImageWithRetry = (imageUrl: string) => { + checkImageReady(imageUrl) + .then(() => { + addSuccessToast(t('The screenshot is now being downloaded.')); + }) + .catch(error => { + // we check how many retries have been made + if (retries < MAX_RETRIES) { + retries += 1; + addInfoToast( + t( + 'The screenshot is being generated. Please, do not leave the page.', + ), + { + noDuplicate: true, + }, + ); + setTimeout(() => fetchImageWithRetry(imageUrl), RETRY_INTERVAL); + } else { + addDangerToast( + t( + 'The screenshot could not be downloaded. Please, try again later.', + ), + ); + logging.error(error); + } + }); + }; + + SupersetClient.post({ + endpoint: `/api/v1/dashboard/${dashboardId}/cache_dashboard_screenshot`, + jsonPayload: { + anchor, + }, + }) + .then(({ json }) => { + const imageUrl = json?.image_url; + if (!imageUrl) { + throw new Error('No image URL in response'); + } + addInfoToast( + t( + 'The screenshot is being generated. Please, do not leave the page.', + ), + ); + fetchImageWithRetry(imageUrl); + }) + .catch(error => { + logging.error(error); + addDangerToast( + t('The screenshot could not be downloaded. Please, try again later.'), + ); + }) + .finally(() => { + logEvent?.( + format === DownloadScreenshotFormat.PNG + ? LOG_ACTIONS_DASHBOARD_DOWNLOAD_AS_IMAGE + : LOG_ACTIONS_DASHBOARD_DOWNLOAD_AS_PDF, + ); + }); + }; + + return ( + +
+ {text} +
+
+ ); +} diff --git a/superset-frontend/src/dashboard/components/menu/DownloadMenuItems/index.tsx b/superset-frontend/src/dashboard/components/menu/DownloadMenuItems/index.tsx index 290d18232..c17fc0d02 100644 --- a/superset-frontend/src/dashboard/components/menu/DownloadMenuItems/index.tsx +++ b/superset-frontend/src/dashboard/components/menu/DownloadMenuItems/index.tsx @@ -17,41 +17,40 @@ * under the License. */ import { Menu } from 'src/components/Menu'; -import DownloadAsImage from './DownloadAsImage'; -import DownloadAsPdf from './DownloadAsPdf'; +import DownloadScreenshot from './DownloadScreenshot'; +import { DownloadScreenshotFormat } from './types'; export interface DownloadMenuItemProps { pdfMenuItemTitle: string; imageMenuItemTitle: string; - addDangerToast: Function; dashboardTitle: string; logEvent?: Function; + dashboardId: string; } const DownloadMenuItems = (props: DownloadMenuItemProps) => { const { pdfMenuItemTitle, imageMenuItemTitle, - addDangerToast, - dashboardTitle, logEvent, + dashboardId, ...rest } = props; return ( - - diff --git a/superset-frontend/src/types/dom-to-pdf.d.ts b/superset-frontend/src/dashboard/components/menu/DownloadMenuItems/types.ts similarity index 70% rename from superset-frontend/src/types/dom-to-pdf.d.ts rename to superset-frontend/src/dashboard/components/menu/DownloadMenuItems/types.ts index 061e80d96..35129532e 100644 --- a/superset-frontend/src/types/dom-to-pdf.d.ts +++ b/superset-frontend/src/dashboard/components/menu/DownloadMenuItems/types.ts @@ -16,21 +16,8 @@ * specific language governing permissions and limitations * under the License. */ -declare module 'dom-to-pdf' { - interface Image { - type: string; - quality: number; - } - interface Options { - margin: number; - filename: string; - image: Image; - html2canvas: object; - excludeClassNames?: string[]; - } - - function domToPdf(elementToPrint: Element, options?: Options): Promise; - - export default domToPdf; +export enum DownloadScreenshotFormat { + PDF = 'pdf', + PNG = 'png', } diff --git a/superset-frontend/src/utils/downloadAsPdf.ts b/superset-frontend/src/utils/downloadAsPdf.ts deleted file mode 100644 index bb769d1eb..000000000 --- a/superset-frontend/src/utils/downloadAsPdf.ts +++ /dev/null @@ -1,74 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -import { SyntheticEvent } from 'react'; -import domToPdf from 'dom-to-pdf'; -import { kebabCase } from 'lodash'; -import { logging, t } from '@superset-ui/core'; -import { addWarningToast } from 'src/components/MessageToasts/actions'; - -/** - * generate a consistent file stem from a description and date - * - * @param description title or description of content of file - * @param date date when file was generated - */ -const generateFileStem = (description: string, date = new Date()) => - `${kebabCase(description)}-${date.toISOString().replace(/[: ]/g, '-')}`; - -/** - * Create an event handler for turning an element into an image - * - * @param selector css selector of the parent element which should be turned into image - * @param description name or a short description of what is being printed. - * Value will be normalized, and a date as well as a file extension will be added. - * @param isExactSelector if false, searches for the closest ancestor that matches selector. - * @returns event handler - */ -export default function downloadAsPdf( - selector: string, - description: string, - isExactSelector = false, -) { - return (event: SyntheticEvent) => { - const elementToPrint = isExactSelector - ? document.querySelector(selector) - : event.currentTarget.closest(selector); - - if (!elementToPrint) { - return addWarningToast( - t('PDF download failed, please refresh and try again.'), - ); - } - - const options = { - margin: 10, - filename: `${generateFileStem(description)}.pdf`, - image: { type: 'jpeg', quality: 1 }, - html2canvas: { scale: 2 }, - excludeClassNames: ['header-controls'], - }; - return domToPdf(elementToPrint, options) - .then(() => { - // nothing to be done - }) - .catch((e: Error) => { - logging.error('PDF generation failed', e); - }); - }; -} diff --git a/superset/tasks/thumbnails.py b/superset/tasks/thumbnails.py index da42b1b14..483fb8495 100644 --- a/superset/tasks/thumbnails.py +++ b/superset/tasks/thumbnails.py @@ -107,12 +107,12 @@ def cache_dashboard_thumbnail( # pylint: disable=too-many-arguments -@celery_app.task(name="cache_dashboard_screenshot", soft_time_limit=60) +@celery_app.task(name="cache_dashboard_screenshot", soft_time_limit=300) def cache_dashboard_screenshot( current_user: Optional[str], dashboard_id: int, dashboard_url: str, - force: bool = False, + force: bool = True, thumb_size: Optional[WindowSize] = None, window_size: Optional[WindowSize] = None, ) -> None: