2021-06-01 14:05:09 +02:00
|
|
|
import React from "react";
|
|
|
|
import { Card } from "../../components/Card";
|
|
|
|
import { ToolButton } from "../../components/ToolButton";
|
|
|
|
import { serializeAsJSON } from "../../data/json";
|
2021-10-21 22:05:48 +02:00
|
|
|
import { loadFirebaseStorage, saveFilesToFirebase } from "../data/firebase";
|
|
|
|
import { FileId, NonDeletedExcalidrawElement } from "../../element/types";
|
|
|
|
import { AppState, BinaryFileData, BinaryFiles } from "../../types";
|
2021-06-01 14:05:09 +02:00
|
|
|
import { nanoid } from "nanoid";
|
2023-02-22 15:01:23 +01:00
|
|
|
import { useI18n } from "../../i18n";
|
2021-10-21 22:05:48 +02:00
|
|
|
import { encryptData, generateEncryptionKey } from "../../data/encryption";
|
|
|
|
import { isInitializedImageElement } from "../../element/typeChecks";
|
|
|
|
import { FILE_UPLOAD_MAX_BYTES } from "../app_constants";
|
|
|
|
import { encodeFilesForUpload } from "../data/FileManager";
|
|
|
|
import { MIME_TYPES } from "../../constants";
|
2022-03-28 14:46:40 +02:00
|
|
|
import { trackEvent } from "../../analytics";
|
|
|
|
import { getFrame } from "../../utils";
|
2023-09-11 17:47:41 +02:00
|
|
|
import { ExcalidrawLogo } from "../../components/ExcalidrawLogo";
|
2021-06-01 14:05:09 +02:00
|
|
|
|
2023-06-19 17:08:12 +02:00
|
|
|
export const exportToExcalidrawPlus = async (
|
2021-06-01 14:05:09 +02:00
|
|
|
elements: readonly NonDeletedExcalidrawElement[],
|
2023-05-08 10:14:02 +02:00
|
|
|
appState: Partial<AppState>,
|
2021-10-21 22:05:48 +02:00
|
|
|
files: BinaryFiles,
|
2021-06-01 14:05:09 +02:00
|
|
|
) => {
|
|
|
|
const firebase = await loadFirebaseStorage();
|
|
|
|
|
|
|
|
const id = `${nanoid(12)}`;
|
|
|
|
|
2021-10-21 22:05:48 +02:00
|
|
|
const encryptionKey = (await generateEncryptionKey())!;
|
2021-06-01 14:05:09 +02:00
|
|
|
const encryptedData = await encryptData(
|
2021-10-21 22:05:48 +02:00
|
|
|
encryptionKey,
|
|
|
|
serializeAsJSON(elements, appState, files, "database"),
|
2021-06-01 14:05:09 +02:00
|
|
|
);
|
|
|
|
|
2021-10-21 22:05:48 +02:00
|
|
|
const blob = new Blob(
|
|
|
|
[encryptedData.iv, new Uint8Array(encryptedData.encryptedBuffer)],
|
|
|
|
{
|
|
|
|
type: MIME_TYPES.binary,
|
|
|
|
},
|
|
|
|
);
|
2021-06-01 14:05:09 +02:00
|
|
|
|
|
|
|
await firebase
|
|
|
|
.storage()
|
|
|
|
.ref(`/migrations/scenes/${id}`)
|
|
|
|
.put(blob, {
|
|
|
|
customMetadata: {
|
2021-10-21 22:05:48 +02:00
|
|
|
data: JSON.stringify({ version: 2, name: appState.name }),
|
2021-06-01 14:05:09 +02:00
|
|
|
created: Date.now().toString(),
|
|
|
|
},
|
|
|
|
});
|
|
|
|
|
2021-10-21 22:05:48 +02:00
|
|
|
const filesMap = new Map<FileId, BinaryFileData>();
|
|
|
|
for (const element of elements) {
|
|
|
|
if (isInitializedImageElement(element) && files[element.fileId]) {
|
|
|
|
filesMap.set(element.fileId, files[element.fileId]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (filesMap.size) {
|
|
|
|
const filesToUpload = await encodeFilesForUpload({
|
|
|
|
files: filesMap,
|
|
|
|
encryptionKey,
|
|
|
|
maxBytes: FILE_UPLOAD_MAX_BYTES,
|
|
|
|
});
|
|
|
|
|
|
|
|
await saveFilesToFirebase({
|
|
|
|
prefix: `/migrations/files/scenes/${id}`,
|
|
|
|
files: filesToUpload,
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
window.open(
|
2023-09-11 23:13:16 +02:00
|
|
|
`${
|
|
|
|
import.meta.env.VITE_APP_PLUS_APP
|
|
|
|
}/import?excalidraw=${id},${encryptionKey}`,
|
2021-10-21 22:05:48 +02:00
|
|
|
);
|
2021-06-01 14:05:09 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
export const ExportToExcalidrawPlus: React.FC<{
|
|
|
|
elements: readonly NonDeletedExcalidrawElement[];
|
2023-05-08 10:14:02 +02:00
|
|
|
appState: Partial<AppState>;
|
2021-10-21 22:05:48 +02:00
|
|
|
files: BinaryFiles;
|
2021-06-01 14:05:09 +02:00
|
|
|
onError: (error: Error) => void;
|
2021-10-21 22:05:48 +02:00
|
|
|
}> = ({ elements, appState, files, onError }) => {
|
2023-02-22 15:01:23 +01:00
|
|
|
const { t } = useI18n();
|
2021-06-01 14:05:09 +02:00
|
|
|
return (
|
2021-12-15 15:31:44 +01:00
|
|
|
<Card color="primary">
|
2023-09-11 17:47:41 +02:00
|
|
|
<div className="Card-icon">
|
|
|
|
<ExcalidrawLogo
|
|
|
|
style={{
|
|
|
|
[`--color-logo-icon` as any]: "#fff",
|
|
|
|
width: "2.8rem",
|
|
|
|
height: "2.8rem",
|
|
|
|
}}
|
|
|
|
/>
|
|
|
|
</div>
|
2021-06-01 14:05:09 +02:00
|
|
|
<h2>Excalidraw+</h2>
|
|
|
|
<div className="Card-details">
|
|
|
|
{t("exportDialog.excalidrawplus_description")}
|
|
|
|
</div>
|
|
|
|
<ToolButton
|
|
|
|
className="Card-button"
|
|
|
|
type="button"
|
|
|
|
title={t("exportDialog.excalidrawplus_button")}
|
|
|
|
aria-label={t("exportDialog.excalidrawplus_button")}
|
|
|
|
showAriaLabel={true}
|
|
|
|
onClick={async () => {
|
|
|
|
try {
|
2022-03-28 14:46:40 +02:00
|
|
|
trackEvent("export", "eplus", `ui (${getFrame()})`);
|
2021-10-21 22:05:48 +02:00
|
|
|
await exportToExcalidrawPlus(elements, appState, files);
|
2021-11-02 14:24:16 +02:00
|
|
|
} catch (error: any) {
|
2021-06-01 14:05:09 +02:00
|
|
|
console.error(error);
|
2021-10-30 23:40:35 +02:00
|
|
|
if (error.name !== "AbortError") {
|
|
|
|
onError(new Error(t("exportDialog.excalidrawplus_exportError")));
|
|
|
|
}
|
2021-06-01 14:05:09 +02:00
|
|
|
}
|
|
|
|
}}
|
|
|
|
/>
|
|
|
|
</Card>
|
|
|
|
);
|
|
|
|
};
|