From 9ccc8bdc0fd3c4d21eeb26a5e467fcf194bee9e2 Mon Sep 17 00:00:00 2001 From: Paul D'Ambra Date: Thu, 23 Mar 2023 15:53:28 +0000 Subject: [PATCH] feat: reduce size of images before uploading to text cards (#14868) * feat: reduce size of images before uploading to text cards * Update UI snapshots for `webkit` (2) * Update UI snapshots for `webkit` (2) * lazily import the blob reducer * no any when not any --------- Co-authored-by: github-actions <41898282+github-actions[bot]@users.noreply.github.com> --- .../lemon-ui/LemonTextArea/LemonTextArea.tsx | 8 +++- package.json | 2 + pnpm-lock.yaml | 43 ++++++++++++++++++- 3 files changed, 50 insertions(+), 3 deletions(-) diff --git a/frontend/src/lib/lemon-ui/LemonTextArea/LemonTextArea.tsx b/frontend/src/lib/lemon-ui/LemonTextArea/LemonTextArea.tsx index 5d3a57ca184..86bf6b2891f 100644 --- a/frontend/src/lib/lemon-ui/LemonTextArea/LemonTextArea.tsx +++ b/frontend/src/lib/lemon-ui/LemonTextArea/LemonTextArea.tsx @@ -14,6 +14,11 @@ import { Link } from 'lib/lemon-ui/Link' import { Tooltip } from 'lib/lemon-ui/Tooltip' import { LemonTabs } from '../LemonTabs' +const lazyBlobReducer = async (f: File): Promise => { + const blobReducer = (await import('image-blob-reduce')).default() + return blobReducer.toBlob(f, { max: 2000 }) +} + export interface LemonTextAreaProps extends Pick< React.TextareaHTMLAttributes, @@ -88,7 +93,8 @@ export function LemonTextMarkdown({ value, onChange, ...editAreaProps }: LemonTe try { setUploading(true) const formData = new FormData() - formData.append('image', filesToUpload[0]) + const reducedBlob = await lazyBlobReducer(filesToUpload[0]) + formData.append('image', reducedBlob) const media = await api.media.upload(formData) onChange?.(value + `\n\n![${media.name}](${media.image_location})`) posthog.capture('markdown image uploaded', { name: media.name }) diff --git a/package.json b/package.json index 2b318ee3c95..399a2b15f6c 100644 --- a/package.json +++ b/package.json @@ -98,6 +98,7 @@ "fs-extra": "^10.0.0", "fuse.js": "^6.4.1", "husky": "^7.0.4", + "image-blob-reduce": "^4.1.0", "kea": "^3.1.5", "kea-forms": "^3.0.3", "kea-loaders": "^3.0.0", @@ -183,6 +184,7 @@ "@types/clone": "^2.1.1", "@types/d3": "^7.4.0", "@types/d3-sankey": "^0.12.1", + "@types/image-blob-reduce": "^4.1.1", "@types/jest": "^29.2.3", "@types/jest-image-snapshot": "^6.1.0", "@types/md5": "^2.3.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 2423dc9c01a..3f0b7e317f5 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -45,6 +45,7 @@ specifiers: '@types/clone': ^2.1.1 '@types/d3': ^7.4.0 '@types/d3-sankey': ^0.12.1 + '@types/image-blob-reduce': ^4.1.1 '@types/jest': ^29.2.3 '@types/jest-image-snapshot': ^6.1.0 '@types/md5': ^2.3.0 @@ -113,6 +114,7 @@ specifiers: html-webpack-harddisk-plugin: ^1.0.2 html-webpack-plugin: ^4.5.2 husky: ^7.0.4 + image-blob-reduce: ^4.1.0 jest: ^29.3.1 jest-canvas-mock: ^2.4.0 jest-environment-jsdom: ^29.3.1 @@ -227,6 +229,7 @@ dependencies: fs-extra: 10.1.0 fuse.js: 6.6.2 husky: 7.0.4 + image-blob-reduce: 4.1.0 kea: 3.1.5_react@16.14.0 kea-forms: 3.0.3_kea@3.1.5 kea-loaders: 3.0.0_kea@3.1.5 @@ -314,6 +317,7 @@ devDependencies: '@types/clone': 2.1.1 '@types/d3': 7.4.0 '@types/d3-sankey': 0.12.1 + '@types/image-blob-reduce': 4.1.1 '@types/jest': 29.2.4 '@types/jest-image-snapshot': 6.1.0 '@types/node': 18.11.9 @@ -4884,6 +4888,12 @@ packages: resolution: {integrity: sha512-h4lTMgMJctJybDp8CQrxTUiiYmedihHWkjnF/8Pxseu2S6Nlfcy8kwboQ8yejh456rP2yWoEVm1sS/FVsfM48w==} dev: true + /@types/image-blob-reduce/4.1.1: + resolution: {integrity: sha512-Oe2EPjW+iZSsXccxZPebqHqXAUaOLir3eQVqPx0ryXeJZdCZx+gYvWBZtqYEcluP6f3bll1m06ahT26bX0+LOg==} + dependencies: + '@types/pica': 9.0.1 + dev: true + /@types/is-function/1.0.1: resolution: {integrity: sha512-A79HEEiwXTFtfY+Bcbo58M2GRYzCr9itHWzbzHVFNEYCcoU/MMGwYYf721gBrnhpj1s6RGVVha/IgNFnR0Iw/Q==} dev: true @@ -4999,6 +5009,10 @@ packages: resolution: {integrity: sha512-kUNnecmtkunAoQ3CnjmMkzNU/gtxG8guhi+Fk2U/kOpIKjIMKnXGp4IJCgQJrXSgMsWYimYG4TGjz/UzbGEBTw==} dev: true + /@types/pica/9.0.1: + resolution: {integrity: sha512-hTsYxcy0MqIOKzeALuh3zOHyozBlndxV/bX9X52GBFq2XUQchZF6T0vcRYeT5P1ggmswi2LlIwHAH+bKWxxalg==} + dev: true + /@types/pixelmatch/5.2.4: resolution: {integrity: sha512-HDaSHIAv9kwpMN7zlmwfTv6gax0PiporJOipcrGsVNF3Ba+kryOZc0Pio5pn6NhisgWr7TaajlPEKTbTAypIBQ==} dependencies: @@ -10423,7 +10437,6 @@ packages: /glur/1.1.2: resolution: {integrity: sha512-l+8esYHTKOx2G/Aao4lEQ0bnHWg4fWtJbVoZZT9Knxi01pB8C80BR85nONLFwkkQoFRCmXY+BUcGZN3yZ2QsRA==} - dev: true /gopd/1.0.1: resolution: {integrity: sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==} @@ -10881,6 +10894,12 @@ packages: engines: {node: '>= 4'} dev: true + /image-blob-reduce/4.1.0: + resolution: {integrity: sha512-iljleP8Fr7tS1ezrAazWi30abNPYXtBGXb9R9oTZDWObqiKq18AQJGTUb0wkBOtdCZ36/IirkuuAIIHTjBJIjA==} + dependencies: + pica: 9.0.1 + dev: false + /image-size/0.5.5: resolution: {integrity: sha512-6TDAlDPZxUFCv+fuOkIoXT/V/f3Qbq8e37p+YOiYrUv3v9cc3/6x78VdfPgFVaB9dZYeLUfKgHRebpkm/oP2VQ==} engines: {node: '>=0.10.0'} @@ -12754,7 +12773,7 @@ packages: dependencies: universalify: 2.0.0 optionalDependencies: - graceful-fs: 4.2.10 + graceful-fs: 4.2.11 /jsprim/2.0.2: resolution: {integrity: sha512-gqXddjPqQ6G40VdnI6T6yObEC+pDNvyP95wdQhkWkg7crHH3km5qP1FsOXEkzEQwnz6gz5qGTn1c2Y52wP3OyQ==} @@ -13718,6 +13737,13 @@ packages: - supports-color dev: true + /multimath/2.0.0: + resolution: {integrity: sha512-toRx66cAMJ+Ccz7pMIg38xSIrtnbozk0dchXezwQDMgQmbGpfxjtv68H+L00iFL8hxDaVjrmwAFSb3I6bg8Q2g==} + dependencies: + glur: 1.1.2 + object-assign: 4.1.1 + dev: false + /mute-stream/0.0.8: resolution: {integrity: sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==} dev: true @@ -14515,6 +14541,15 @@ packages: resolution: {integrity: sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==} dev: true + /pica/9.0.1: + resolution: {integrity: sha512-v0U4vY6Z3ztz9b4jBIhCD3WYoecGXCQeCsYep+sXRefViL+mVVoTL+wqzdPeE+GpBFsRUtQZb6dltvAt2UkMtQ==} + dependencies: + glur: 1.1.2 + multimath: 2.0.0 + object-assign: 4.1.1 + webworkify: 1.5.0 + dev: false + /picocolors/0.2.1: resolution: {integrity: sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==} dev: true @@ -18926,6 +18961,10 @@ packages: - supports-color dev: true + /webworkify/1.5.0: + resolution: {integrity: sha512-AMcUeyXAhbACL8S2hqqdqOLqvJ8ylmIbNwUIqQujRSouf4+eUFaXbG6F1Rbu+srlJMmxQWsiU7mOJi0nMBfM1g==} + dev: false + /whatwg-encoding/2.0.0: resolution: {integrity: sha512-p41ogyeMUrw3jWclHWTQg1k05DSVXPLcVxRTYsXUk+ZooOCZLcoYgPZ/HL/D/N+uQPOtcp1me1WhBEaX02mhWg==} engines: {node: '>=12'}