mirror of
https://github.com/stonith404/pingvin-share.git
synced 2025-02-19 01:55:48 -05:00
Add function to download all files as a zip
This commit is contained in:
parent
7ddce593f9
commit
b070f17d67
7 changed files with 265 additions and 16 deletions
|
@ -50,6 +50,12 @@ Without docker:
|
|||
1. Run `npm install`
|
||||
2. Run `npm run build && npm run start`
|
||||
|
||||
|
||||
## Known issues / Limitations
|
||||
Pingvin Share is currently in beta and there are issues and limitations that should be fixed in the future.
|
||||
- `DownloadAll` generates the zip file on the client side. This takes alot of time. Because of that I temporarily limited this function to maximal 150 MB.
|
||||
- If a user knows the share id, he can list and download the files directly from the Appwrite API even if the share is secured by a password or a visitor limit.
|
||||
|
||||
## Contribute
|
||||
|
||||
You're very welcome to contribute to Pingvin Share!
|
||||
|
|
152
package-lock.json
generated
152
package-lock.json
generated
|
@ -19,7 +19,9 @@
|
|||
"axios": "^0.26.1",
|
||||
"cookie": "^0.5.0",
|
||||
"cookies-next": "^2.0.4",
|
||||
"file-saver": "^2.0.5",
|
||||
"js-file-download": "^0.4.12",
|
||||
"jszip": "^3.9.1",
|
||||
"next": "12.1.5",
|
||||
"next-pwa": "^5.5.2",
|
||||
"node-appwrite": "^5.1.0",
|
||||
|
@ -30,6 +32,7 @@
|
|||
},
|
||||
"devDependencies": {
|
||||
"@types/cookie": "^0.5.0",
|
||||
"@types/file-saver": "^2.0.5",
|
||||
"@types/node": "17.0.23",
|
||||
"@types/react": "18.0.4",
|
||||
"@types/react-dom": "18.0.0",
|
||||
|
@ -2527,6 +2530,12 @@
|
|||
"integrity": "sha512-CuPgU6f3eT/XgKKPqKd/gLZV1Xmvf1a2R5POBOGQa6uv82xpls89HU5zKeVoyR8XzHd1RGNOlQlvUe3CFkjWNQ==",
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/@types/file-saver": {
|
||||
"version": "2.0.5",
|
||||
"resolved": "https://registry.npmjs.org/@types/file-saver/-/file-saver-2.0.5.tgz",
|
||||
"integrity": "sha512-zv9kNf3keYegP5oThGLaPk8E081DFDuwfqjtiTzm6PoxChdJ1raSuADf2YGCVIyrSynLrgc8JWv296s7Q7pQSQ==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@types/glob": {
|
||||
"version": "7.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.2.0.tgz",
|
||||
|
@ -4455,6 +4464,11 @@
|
|||
"node": "^10.12.0 || >=12.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/file-saver": {
|
||||
"version": "2.0.5",
|
||||
"resolved": "https://registry.npmjs.org/file-saver/-/file-saver-2.0.5.tgz",
|
||||
"integrity": "sha512-P9bmyZ3h/PRG+Nzga+rbdI4OEpNDzAVyy74uVO9ATgzLK6VtAsYybF/+TOCvrc0MO793d6+42lLyZTw7/ArVzA=="
|
||||
},
|
||||
"node_modules/file-selector": {
|
||||
"version": "0.4.0",
|
||||
"resolved": "https://registry.npmjs.org/file-selector/-/file-selector-0.4.0.tgz",
|
||||
|
@ -4895,6 +4909,11 @@
|
|||
"node": ">= 4"
|
||||
}
|
||||
},
|
||||
"node_modules/immediate": {
|
||||
"version": "3.0.6",
|
||||
"resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz",
|
||||
"integrity": "sha1-nbHb0Pr43m++D13V5Wu2BigN5ps="
|
||||
},
|
||||
"node_modules/import-fresh": {
|
||||
"version": "3.3.0",
|
||||
"resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz",
|
||||
|
@ -5364,6 +5383,44 @@
|
|||
"node": ">=4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/jszip": {
|
||||
"version": "3.9.1",
|
||||
"resolved": "https://registry.npmjs.org/jszip/-/jszip-3.9.1.tgz",
|
||||
"integrity": "sha512-H9A60xPqJ1CuC4Ka6qxzXZeU8aNmgOeP5IFqwJbQQwtu2EUYxota3LdsiZWplF7Wgd9tkAd0mdu36nceSaPuYw==",
|
||||
"dependencies": {
|
||||
"lie": "~3.3.0",
|
||||
"pako": "~1.0.2",
|
||||
"readable-stream": "~2.3.6",
|
||||
"set-immediate-shim": "~1.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/jszip/node_modules/isarray": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
|
||||
"integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE="
|
||||
},
|
||||
"node_modules/jszip/node_modules/readable-stream": {
|
||||
"version": "2.3.7",
|
||||
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz",
|
||||
"integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==",
|
||||
"dependencies": {
|
||||
"core-util-is": "~1.0.0",
|
||||
"inherits": "~2.0.3",
|
||||
"isarray": "~1.0.0",
|
||||
"process-nextick-args": "~2.0.0",
|
||||
"safe-buffer": "~5.1.1",
|
||||
"string_decoder": "~1.1.1",
|
||||
"util-deprecate": "~1.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/jszip/node_modules/string_decoder": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
|
||||
"integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
|
||||
"dependencies": {
|
||||
"safe-buffer": "~5.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/language-subtag-registry": {
|
||||
"version": "0.3.21",
|
||||
"resolved": "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.21.tgz",
|
||||
|
@ -5400,6 +5457,14 @@
|
|||
"node": ">= 0.8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/lie": {
|
||||
"version": "3.3.0",
|
||||
"resolved": "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz",
|
||||
"integrity": "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==",
|
||||
"dependencies": {
|
||||
"immediate": "~3.0.5"
|
||||
}
|
||||
},
|
||||
"node_modules/lines-and-columns": {
|
||||
"version": "1.2.4",
|
||||
"resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz",
|
||||
|
@ -5950,6 +6015,11 @@
|
|||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/pako": {
|
||||
"version": "1.0.11",
|
||||
"resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz",
|
||||
"integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw=="
|
||||
},
|
||||
"node_modules/parent-module": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
|
||||
|
@ -6597,6 +6667,14 @@
|
|||
"randombytes": "^2.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/set-immediate-shim": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz",
|
||||
"integrity": "sha1-SysbJ+uAip+NzEgaWOXlb1mfP2E=",
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/shebang-command": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
|
||||
|
@ -9469,6 +9547,12 @@
|
|||
"integrity": "sha512-CuPgU6f3eT/XgKKPqKd/gLZV1Xmvf1a2R5POBOGQa6uv82xpls89HU5zKeVoyR8XzHd1RGNOlQlvUe3CFkjWNQ==",
|
||||
"peer": true
|
||||
},
|
||||
"@types/file-saver": {
|
||||
"version": "2.0.5",
|
||||
"resolved": "https://registry.npmjs.org/@types/file-saver/-/file-saver-2.0.5.tgz",
|
||||
"integrity": "sha512-zv9kNf3keYegP5oThGLaPk8E081DFDuwfqjtiTzm6PoxChdJ1raSuADf2YGCVIyrSynLrgc8JWv296s7Q7pQSQ==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/glob": {
|
||||
"version": "7.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.2.0.tgz",
|
||||
|
@ -10991,6 +11075,11 @@
|
|||
"flat-cache": "^3.0.4"
|
||||
}
|
||||
},
|
||||
"file-saver": {
|
||||
"version": "2.0.5",
|
||||
"resolved": "https://registry.npmjs.org/file-saver/-/file-saver-2.0.5.tgz",
|
||||
"integrity": "sha512-P9bmyZ3h/PRG+Nzga+rbdI4OEpNDzAVyy74uVO9ATgzLK6VtAsYybF/+TOCvrc0MO793d6+42lLyZTw7/ArVzA=="
|
||||
},
|
||||
"file-selector": {
|
||||
"version": "0.4.0",
|
||||
"resolved": "https://registry.npmjs.org/file-selector/-/file-selector-0.4.0.tgz",
|
||||
|
@ -11314,6 +11403,11 @@
|
|||
"resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz",
|
||||
"integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ=="
|
||||
},
|
||||
"immediate": {
|
||||
"version": "3.0.6",
|
||||
"resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz",
|
||||
"integrity": "sha1-nbHb0Pr43m++D13V5Wu2BigN5ps="
|
||||
},
|
||||
"import-fresh": {
|
||||
"version": "3.3.0",
|
||||
"resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz",
|
||||
|
@ -11648,6 +11742,46 @@
|
|||
"object.assign": "^4.1.2"
|
||||
}
|
||||
},
|
||||
"jszip": {
|
||||
"version": "3.9.1",
|
||||
"resolved": "https://registry.npmjs.org/jszip/-/jszip-3.9.1.tgz",
|
||||
"integrity": "sha512-H9A60xPqJ1CuC4Ka6qxzXZeU8aNmgOeP5IFqwJbQQwtu2EUYxota3LdsiZWplF7Wgd9tkAd0mdu36nceSaPuYw==",
|
||||
"requires": {
|
||||
"lie": "~3.3.0",
|
||||
"pako": "~1.0.2",
|
||||
"readable-stream": "~2.3.6",
|
||||
"set-immediate-shim": "~1.0.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"isarray": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
|
||||
"integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE="
|
||||
},
|
||||
"readable-stream": {
|
||||
"version": "2.3.7",
|
||||
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz",
|
||||
"integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==",
|
||||
"requires": {
|
||||
"core-util-is": "~1.0.0",
|
||||
"inherits": "~2.0.3",
|
||||
"isarray": "~1.0.0",
|
||||
"process-nextick-args": "~2.0.0",
|
||||
"safe-buffer": "~5.1.1",
|
||||
"string_decoder": "~1.1.1",
|
||||
"util-deprecate": "~1.0.1"
|
||||
}
|
||||
},
|
||||
"string_decoder": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
|
||||
"integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
|
||||
"requires": {
|
||||
"safe-buffer": "~5.1.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"language-subtag-registry": {
|
||||
"version": "0.3.21",
|
||||
"resolved": "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.21.tgz",
|
||||
|
@ -11678,6 +11812,14 @@
|
|||
"type-check": "~0.4.0"
|
||||
}
|
||||
},
|
||||
"lie": {
|
||||
"version": "3.3.0",
|
||||
"resolved": "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz",
|
||||
"integrity": "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==",
|
||||
"requires": {
|
||||
"immediate": "~3.0.5"
|
||||
}
|
||||
},
|
||||
"lines-and-columns": {
|
||||
"version": "1.2.4",
|
||||
"resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz",
|
||||
|
@ -12080,6 +12222,11 @@
|
|||
"integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=",
|
||||
"dev": true
|
||||
},
|
||||
"pako": {
|
||||
"version": "1.0.11",
|
||||
"resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz",
|
||||
"integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw=="
|
||||
},
|
||||
"parent-module": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
|
||||
|
@ -12536,6 +12683,11 @@
|
|||
"randombytes": "^2.1.0"
|
||||
}
|
||||
},
|
||||
"set-immediate-shim": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz",
|
||||
"integrity": "sha1-SysbJ+uAip+NzEgaWOXlb1mfP2E="
|
||||
},
|
||||
"shebang-command": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
|
||||
|
|
|
@ -22,7 +22,9 @@
|
|||
"axios": "^0.26.1",
|
||||
"cookie": "^0.5.0",
|
||||
"cookies-next": "^2.0.4",
|
||||
"file-saver": "^2.0.5",
|
||||
"js-file-download": "^0.4.12",
|
||||
"jszip": "^3.9.1",
|
||||
"next": "12.1.5",
|
||||
"next-pwa": "^5.5.2",
|
||||
"node-appwrite": "^5.1.0",
|
||||
|
@ -33,6 +35,7 @@
|
|||
},
|
||||
"devDependencies": {
|
||||
"@types/cookie": "^0.5.0",
|
||||
"@types/file-saver": "^2.0.5",
|
||||
"@types/node": "17.0.23",
|
||||
"@types/react": "18.0.4",
|
||||
"@types/react-dom": "18.0.0",
|
||||
|
|
67
src/components/share/DownloadAllButton.tsx
Normal file
67
src/components/share/DownloadAllButton.tsx
Normal file
|
@ -0,0 +1,67 @@
|
|||
import { Tooltip, Button } from "@mantine/core";
|
||||
import saveAs from "file-saver";
|
||||
import JSZip from "jszip";
|
||||
import { Dispatch, SetStateAction, useState } from "react";
|
||||
import { AppwriteFileWithPreview } from "../../types/File.type";
|
||||
import aw from "../../utils/appwrite.util";
|
||||
|
||||
const DownloadAllButton = ({
|
||||
shareId,
|
||||
files,
|
||||
setFiles,
|
||||
}: {
|
||||
shareId: string;
|
||||
files: AppwriteFileWithPreview[];
|
||||
setFiles: Dispatch<SetStateAction<AppwriteFileWithPreview[]>>;
|
||||
}) => {
|
||||
const [isLoading, setIsLoading] = useState<boolean>(false);
|
||||
const downloadAll = async () => {
|
||||
setIsLoading(true);
|
||||
var zip = new JSZip();
|
||||
for (let i = 0; i < files.length; i++) {
|
||||
files[i].uploadingState = "inProgress";
|
||||
setFiles([...files]);
|
||||
zip.file(
|
||||
files[i].name,
|
||||
await (
|
||||
await fetch(
|
||||
aw.storage.getFileDownload(shareId, files[i].$id).toString()
|
||||
)
|
||||
).blob()
|
||||
);
|
||||
files[i].uploadingState = "finished";
|
||||
setFiles([...files]);
|
||||
}
|
||||
zip.generateAsync({ type: "blob" }).then(function (content) {
|
||||
setIsLoading(false);
|
||||
saveAs(content, `${shareId}-pingvin-share.zip`);
|
||||
});
|
||||
};
|
||||
const isFileTooBig = () => {
|
||||
let shareSize = 0;
|
||||
files.forEach((file) => (shareSize = +file.sizeOriginal));
|
||||
return 150000000 > shareSize;
|
||||
};
|
||||
|
||||
if (!isFileTooBig())
|
||||
return (
|
||||
<Tooltip
|
||||
wrapLines
|
||||
position="bottom"
|
||||
width={220}
|
||||
withArrow
|
||||
label="Only available if your share is smaller than 150 MB."
|
||||
>
|
||||
<Button variant="outline" onClick={downloadAll} disabled>
|
||||
Download all
|
||||
</Button>
|
||||
</Tooltip>
|
||||
);
|
||||
return (
|
||||
<Button variant="outline" loading={isLoading} onClick={downloadAll}>
|
||||
Download all
|
||||
</Button>
|
||||
);
|
||||
};
|
||||
|
||||
export default DownloadAllButton;
|
|
@ -1,7 +1,7 @@
|
|||
import { ActionIcon, Skeleton, Table } from "@mantine/core";
|
||||
import { ActionIcon, Loader, Skeleton, Table } from "@mantine/core";
|
||||
import Image from "next/image";
|
||||
import { useRouter } from "next/router";
|
||||
import { Download } from "tabler-icons-react";
|
||||
import { CircleCheck, Download } from "tabler-icons-react";
|
||||
import { AppwriteFileWithPreview } from "../../types/File.type";
|
||||
import aw from "../../utils/appwrite.util";
|
||||
import { bytesToSize } from "../../utils/math/byteToSize.util";
|
||||
|
@ -50,14 +50,22 @@ const FileList = ({
|
|||
<td>{file.name}</td>
|
||||
<td>{bytesToSize(file.sizeOriginal)}</td>
|
||||
<td>
|
||||
<ActionIcon
|
||||
size={25}
|
||||
onClick={() =>
|
||||
router.push(aw.storage.getFileDownload(shareId, file.$id))
|
||||
}
|
||||
>
|
||||
<Download />
|
||||
</ActionIcon>
|
||||
{file.uploadingState ? (
|
||||
file.uploadingState != "finished" ? (
|
||||
<Loader size={22} />
|
||||
) : (
|
||||
<CircleCheck color="green" size={22} />
|
||||
)
|
||||
) : (
|
||||
<ActionIcon
|
||||
size={25}
|
||||
onClick={() =>
|
||||
router.push(aw.storage.getFileDownload(shareId, file.$id))
|
||||
}
|
||||
>
|
||||
<Download />
|
||||
</ActionIcon>
|
||||
)}
|
||||
</td>
|
||||
</tr>
|
||||
));
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
import { Group } from "@mantine/core";
|
||||
import { useModals } from "@mantine/modals";
|
||||
import { useRouter } from "next/router";
|
||||
import { useEffect, useState } from "react";
|
||||
import Meta from "../../components/Meta";
|
||||
import DownloadAllButton from "../../components/share/DownloadAllButton";
|
||||
import FileList from "../../components/share/FileList";
|
||||
import showEnterPasswordModal from "../../components/share/showEnterPasswordModal";
|
||||
import showShareNotFoundModal from "../../components/share/showShareNotFoundModal";
|
||||
|
@ -13,7 +15,7 @@ const Share = () => {
|
|||
const router = useRouter();
|
||||
const modals = useModals();
|
||||
const shareId = router.query.shareId as string;
|
||||
const [shareList, setShareList] = useState<AppwriteFileWithPreview[]>([]);
|
||||
const [fileList, setFileList] = useState<AppwriteFileWithPreview[]>([]);
|
||||
|
||||
const submitPassword = async (password: string) => {
|
||||
await shareService.authenticateWithPassword(shareId, password).then(() => {
|
||||
|
@ -25,7 +27,9 @@ const Share = () => {
|
|||
const getFiles = (password?: string) =>
|
||||
shareService
|
||||
.get(shareId, password)
|
||||
.then((files) => setShareList(files))
|
||||
.then((files) => {
|
||||
setFileList(files);
|
||||
})
|
||||
.catch((e) => {
|
||||
const error = e.response.data.message;
|
||||
if (e.response.status == 404) {
|
||||
|
@ -44,10 +48,17 @@ const Share = () => {
|
|||
return (
|
||||
<>
|
||||
<Meta title={`Share ${shareId}`} />
|
||||
<Group position="right">
|
||||
<DownloadAllButton
|
||||
shareId={shareId}
|
||||
files={fileList}
|
||||
setFiles={setFileList}
|
||||
/>
|
||||
</Group>
|
||||
<FileList
|
||||
files={shareList}
|
||||
files={fileList}
|
||||
shareId={shareId}
|
||||
isLoading={shareList.length == 0}
|
||||
isLoading={fileList.length == 0}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
|
|
|
@ -3,5 +3,7 @@ import { Models } from "appwrite";
|
|||
export type FileUpload = File & { uploadingState?: UploadState };
|
||||
export type UploadState = "finished" | "inProgress" | undefined;
|
||||
|
||||
export type AppwriteFileWithPreview = Models.File & { preview: Buffer };
|
||||
|
||||
export interface AppwriteFileWithPreview extends Models.File {
|
||||
uploadingState?: UploadState;
|
||||
preview: Buffer;
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue