integrate deletion to collab sessions
This commit is contained in:
parent
f71c200106
commit
08a39e2034
@ -23,6 +23,7 @@ export enum WS_SUBTYPES {
|
|||||||
INVALID_RESPONSE = "INVALID_RESPONSE",
|
INVALID_RESPONSE = "INVALID_RESPONSE",
|
||||||
INIT = "SCENE_INIT",
|
INIT = "SCENE_INIT",
|
||||||
UPDATE = "SCENE_UPDATE",
|
UPDATE = "SCENE_UPDATE",
|
||||||
|
DELETE = "SCENE_DELETE",
|
||||||
MOUSE_LOCATION = "MOUSE_LOCATION",
|
MOUSE_LOCATION = "MOUSE_LOCATION",
|
||||||
IDLE_STATUS = "IDLE_STATUS",
|
IDLE_STATUS = "IDLE_STATUS",
|
||||||
USER_VISIBLE_SCENE_BOUNDS = "USER_VISIBLE_SCENE_BOUNDS",
|
USER_VISIBLE_SCENE_BOUNDS = "USER_VISIBLE_SCENE_BOUNDS",
|
||||||
|
@ -72,6 +72,7 @@ import {
|
|||||||
} from "../data/FileManager";
|
} from "../data/FileManager";
|
||||||
import { LocalData } from "../data/LocalData";
|
import { LocalData } from "../data/LocalData";
|
||||||
import {
|
import {
|
||||||
|
deleteRoomFromFirebase,
|
||||||
isSavedToFirebase,
|
isSavedToFirebase,
|
||||||
loadFilesFromFirebase,
|
loadFilesFromFirebase,
|
||||||
loadFromFirebase,
|
loadFromFirebase,
|
||||||
@ -115,6 +116,7 @@ export interface CollabAPI {
|
|||||||
onPointerUpdate: CollabInstance["onPointerUpdate"];
|
onPointerUpdate: CollabInstance["onPointerUpdate"];
|
||||||
startCollaboration: CollabInstance["startCollaboration"];
|
startCollaboration: CollabInstance["startCollaboration"];
|
||||||
stopCollaboration: CollabInstance["stopCollaboration"];
|
stopCollaboration: CollabInstance["stopCollaboration"];
|
||||||
|
deleteRoom: CollabInstance["deleteRoom"];
|
||||||
syncElements: CollabInstance["syncElements"];
|
syncElements: CollabInstance["syncElements"];
|
||||||
fetchImageFilesFromFirebase: CollabInstance["fetchImageFilesFromFirebase"];
|
fetchImageFilesFromFirebase: CollabInstance["fetchImageFilesFromFirebase"];
|
||||||
setUsername: CollabInstance["setUsername"];
|
setUsername: CollabInstance["setUsername"];
|
||||||
@ -228,6 +230,7 @@ class Collab extends PureComponent<CollabProps, CollabState> {
|
|||||||
isCollaborating: this.isCollaborating,
|
isCollaborating: this.isCollaborating,
|
||||||
onPointerUpdate: this.onPointerUpdate,
|
onPointerUpdate: this.onPointerUpdate,
|
||||||
startCollaboration: this.startCollaboration,
|
startCollaboration: this.startCollaboration,
|
||||||
|
deleteRoom: this.deleteRoom,
|
||||||
syncElements: this.syncElements,
|
syncElements: this.syncElements,
|
||||||
fetchImageFilesFromFirebase: this.fetchImageFilesFromFirebase,
|
fetchImageFilesFromFirebase: this.fetchImageFilesFromFirebase,
|
||||||
stopCollaboration: this.stopCollaboration,
|
stopCollaboration: this.stopCollaboration,
|
||||||
@ -675,6 +678,18 @@ class Collab extends PureComponent<CollabProps, CollabState> {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case WS_SUBTYPES.DELETE: {
|
||||||
|
const { roomId } = decryptedData.payload;
|
||||||
|
if (this.portal.roomId === roomId) {
|
||||||
|
this.destroySocketClient({ isUnload: true });
|
||||||
|
this.setIsCollaborating(false);
|
||||||
|
this.setActiveRoomLink(null);
|
||||||
|
this.setErrorDialog(t("alerts.collabRoomDeleted"));
|
||||||
|
window.history.pushState({}, APP_NAME, window.location.origin);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
default: {
|
default: {
|
||||||
assertNever(decryptedData, null);
|
assertNever(decryptedData, null);
|
||||||
}
|
}
|
||||||
@ -894,6 +909,42 @@ class Collab extends PureComponent<CollabProps, CollabState> {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
deleteRoom = async (): Promise<void> => {
|
||||||
|
if (!this.portal.socket || !this.portal.roomId) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const { roomId, roomKey } = this.portal;
|
||||||
|
if (!roomId || !roomKey) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const link = this.getActiveRoomLink();
|
||||||
|
if (!link) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// check if the room belongs to the current user
|
||||||
|
const isOwner = await roomManager.isRoomOwnedByUser(link);
|
||||||
|
|
||||||
|
if (!isOwner) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
this.portal.broadcastRoomDeletion();
|
||||||
|
await deleteRoomFromFirebase(roomId, roomKey);
|
||||||
|
await roomManager.deleteRoom(roomId);
|
||||||
|
this.stopCollaboration(false);
|
||||||
|
this.setActiveRoomLink(null);
|
||||||
|
window.history.pushState({}, APP_NAME, window.location.origin);
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Failed to delete room:", error);
|
||||||
|
this.setErrorDialog(t("errors.roomDeletionFailed"));
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
public setLastBroadcastedOrReceivedSceneVersion = (version: number) => {
|
public setLastBroadcastedOrReceivedSceneVersion = (version: number) => {
|
||||||
this.lastBroadcastedOrReceivedSceneVersion = version;
|
this.lastBroadcastedOrReceivedSceneVersion = version;
|
||||||
};
|
};
|
||||||
|
@ -252,6 +252,20 @@ class Portal {
|
|||||||
this.socket.emit(WS_EVENTS.USER_FOLLOW_CHANGE, payload);
|
this.socket.emit(WS_EVENTS.USER_FOLLOW_CHANGE, payload);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
broadcastRoomDeletion = async () => {
|
||||||
|
if (this.socket?.id) {
|
||||||
|
const data: SocketUpdateDataSource["ROOM_DELETED"] = {
|
||||||
|
type: WS_SUBTYPES.DELETE,
|
||||||
|
payload: {
|
||||||
|
socketId: this.socket.id as SocketId,
|
||||||
|
roomId: this.roomId!,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
this._broadcastSocketData(data as SocketUpdateData);
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export default Portal;
|
export default Portal;
|
||||||
|
@ -315,3 +315,10 @@ export const loadFilesFromFirebase = async (
|
|||||||
|
|
||||||
return { loadedFiles, erroredFiles };
|
return { loadedFiles, erroredFiles };
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const deleteRoomFromFirebase = async (
|
||||||
|
roomId: string,
|
||||||
|
roomKey: string,
|
||||||
|
): Promise<void> => {
|
||||||
|
// TODO: delete the room...
|
||||||
|
};
|
||||||
|
@ -119,6 +119,13 @@ export type SocketUpdateDataSource = {
|
|||||||
username: string;
|
username: string;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
ROOM_DELETED: {
|
||||||
|
type: WS_SUBTYPES.DELETE;
|
||||||
|
payload: {
|
||||||
|
socketId: SocketId;
|
||||||
|
roomId: string;
|
||||||
|
};
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export type SocketUpdateDataIncoming =
|
export type SocketUpdateDataIncoming =
|
||||||
@ -310,7 +317,7 @@ export const exportToBackend = async (
|
|||||||
|
|
||||||
const response = await fetch(BACKEND_V2_POST, {
|
const response = await fetch(BACKEND_V2_POST, {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
body: payload.buffer,
|
body: new Uint8Array(payload.buffer),
|
||||||
});
|
});
|
||||||
const json = await response.json();
|
const json = await response.json();
|
||||||
if (json.id) {
|
if (json.id) {
|
||||||
|
@ -186,7 +186,7 @@ class RoomManager {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const [, roomId] = match;
|
const roomId = match[1];
|
||||||
return rooms.some((room) => room.roomId === roomId);
|
return rooms.some((room) => room.roomId === roomId);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.warn("Failed to check room ownership:", error);
|
console.warn("Failed to check room ownership:", error);
|
||||||
|
@ -198,10 +198,10 @@ const ActiveRoomDialog = ({
|
|||||||
color="danger"
|
color="danger"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
trackEvent("share", "room deleted");
|
trackEvent("share", "room deleted");
|
||||||
// TODO: handle deletion
|
collabAPI.deleteRoom();
|
||||||
// 1. stop collaboration (for all users?)
|
if (!collabAPI.isCollaborating()) {
|
||||||
// 2. delete room from backend (firebase)
|
handleClose();
|
||||||
// 3. close
|
}
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
@ -253,7 +253,8 @@
|
|||||||
"resetLibrary": "This will clear your library. Are you sure?",
|
"resetLibrary": "This will clear your library. Are you sure?",
|
||||||
"removeItemsFromsLibrary": "Delete {{count}} item(s) from library?",
|
"removeItemsFromsLibrary": "Delete {{count}} item(s) from library?",
|
||||||
"invalidEncryptionKey": "Encryption key must be of 22 characters. Live collaboration is disabled.",
|
"invalidEncryptionKey": "Encryption key must be of 22 characters. Live collaboration is disabled.",
|
||||||
"collabOfflineWarning": "No internet connection available.\nYour changes will not be saved!"
|
"collabOfflineWarning": "No internet connection available.\nYour changes will not be saved!",
|
||||||
|
"collabRoomDeleted": "This collab room has been deleted by its owner."
|
||||||
},
|
},
|
||||||
"errors": {
|
"errors": {
|
||||||
"unsupportedFileType": "Unsupported file type.",
|
"unsupportedFileType": "Unsupported file type.",
|
||||||
@ -280,7 +281,8 @@
|
|||||||
},
|
},
|
||||||
"asyncPasteFailedOnRead": "Couldn't paste (couldn't read from system clipboard).",
|
"asyncPasteFailedOnRead": "Couldn't paste (couldn't read from system clipboard).",
|
||||||
"asyncPasteFailedOnParse": "Couldn't paste.",
|
"asyncPasteFailedOnParse": "Couldn't paste.",
|
||||||
"copyToSystemClipboardFailed": "Couldn't copy to clipboard."
|
"copyToSystemClipboardFailed": "Couldn't copy to clipboard.",
|
||||||
|
"roomDeletionFailed": "Couldn't delete the collaboration room."
|
||||||
},
|
},
|
||||||
"toolBar": {
|
"toolBar": {
|
||||||
"selection": "Selection",
|
"selection": "Selection",
|
||||||
|
Loading…
x
Reference in New Issue
Block a user