This commit is contained in:
Shivansh Kumar 2025-05-01 19:56:05 +00:00 committed by GitHub
commit dcd010c475
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 29 additions and 13 deletions

View file

@ -482,7 +482,7 @@ const ExcalidrawWrapper = () => {
collabAPI?.isCollaborating() && collabAPI?.isCollaborating() &&
!isCollaborationLink(window.location.href) !isCollaborationLink(window.location.href)
) { ) {
collabAPI.stopCollaboration(false); await collabAPI.stopCollaboration(false);
} }
excalidrawAPI.updateScene({ appState: { isLoading: true } }); excalidrawAPI.updateScene({ appState: { isLoading: true } });
@ -980,9 +980,9 @@ const ExcalidrawWrapper = () => {
"exit", "exit",
"collaboration", "collaboration",
], ],
perform: () => { perform: async () => {
if (collabAPI) { if (collabAPI) {
collabAPI.stopCollaboration(); await collabAPI.stopCollaboration();
if (!collabAPI.isCollaborating()) { if (!collabAPI.isCollaborating()) {
setShareDialogState({ isOpen: false }); setShareDialogState({ isOpen: false });
} }

View file

@ -352,13 +352,14 @@ class Collab extends PureComponent<CollabProps, CollabState> {
} }
}; };
stopCollaboration = (keepRemoteState = true) => { stopCollaboration = async (keepRemoteState = true) => {
this.queueBroadcastAllElements.cancel(); this.queueBroadcastAllElements.cancel();
this.queueSaveToFirebase.cancel(); this.queueSaveToFirebase.cancel();
this.loadImageFiles.cancel(); this.loadImageFiles.cancel();
this.resetErrorIndicator(true); this.resetErrorIndicator(true);
this.saveCollabRoomToFirebase( // Ensure we save the latest state before stopping collaboration
await this.saveCollabRoomToFirebase(
getSyncableElements( getSyncableElements(
this.excalidrawAPI.getSceneElementsIncludingDeleted(), this.excalidrawAPI.getSceneElementsIncludingDeleted(),
), ),
@ -379,6 +380,9 @@ class Collab extends PureComponent<CollabProps, CollabState> {
// that could have been saved in other tabs while we were collaborating // that could have been saved in other tabs while we were collaborating
resetBrowserStateVersions(); resetBrowserStateVersions();
// Ensure all pending changes are saved before pushing new state
this.queueSaveToFirebase.flush();
window.history.pushState({}, APP_NAME, window.location.origin); window.history.pushState({}, APP_NAME, window.location.origin);
this.destroySocketClient(); this.destroySocketClient();
@ -950,9 +954,9 @@ class Collab extends PureComponent<CollabProps, CollabState> {
}, SYNC_FULL_SCENE_INTERVAL_MS); }, SYNC_FULL_SCENE_INTERVAL_MS);
queueSaveToFirebase = throttle( queueSaveToFirebase = throttle(
() => { async () => {
if (this.portal.socketInitialized) { if (this.portal.socketInitialized) {
this.saveCollabRoomToFirebase( await this.saveCollabRoomToFirebase(
getSyncableElements( getSyncableElements(
this.excalidrawAPI.getSceneElementsIncludingDeleted(), this.excalidrawAPI.getSceneElementsIncludingDeleted(),
), ),

View file

@ -165,10 +165,9 @@ const ActiveRoomDialog = ({
icon={playerStopFilledIcon} icon={playerStopFilledIcon}
onClick={() => { onClick={() => {
trackEvent("share", "room closed"); trackEvent("share", "room closed");
collabAPI.stopCollaboration(); collabAPI.stopCollaboration().then(() => {
if (!collabAPI.isCollaborating()) {
handleClose(); handleClose();
} });
}} }}
/> />
</div> </div>

View file

@ -2333,7 +2333,7 @@ class App extends React.Component<AppProps, AppState> {
this.setState((state) => ({ this.setState((state) => ({
...getDefaultAppState(), ...getDefaultAppState(),
isLoading: opts?.resetLoadingState ? false : state.isLoading, isLoading: opts?.resetLoadingState ? false : state.isLoading,
theme: this.state.theme, theme: state.theme,
})); }));
this.resetStore(); this.resetStore();
this.resetHistory(); this.resetHistory();
@ -2956,10 +2956,23 @@ class App extends React.Component<AppProps, AppState> {
// init, which would trigger onChange with empty elements, which would then // init, which would trigger onChange with empty elements, which would then
// override whatever is in localStorage currently. // override whatever is in localStorage currently.
if (!this.state.isLoading) { if (!this.state.isLoading) {
// Only trigger onChange when there are actual changes to elements or important app state
const prevElements = this.scene.getElementsIncludingDeleted();
const hasElementChanges = elements.length !== prevElements.length ||
elements.some((element, index) => element !== prevElements[index]);
const hasImportantStateChanges =
this.state.selectedElementIds !== prevState.selectedElementIds ||
this.state.width !== prevState.width ||
this.state.height !== prevState.height ||
this.state.editingTextElement !== prevState.editingTextElement;
if (hasElementChanges || hasImportantStateChanges) {
this.props.onChange?.(elements, this.state, this.files); this.props.onChange?.(elements, this.state, this.files);
this.onChangeEmitter.trigger(elements, this.state, this.files); this.onChangeEmitter.trigger(elements, this.state, this.files);
} }
} }
}
private renderInteractiveSceneCallback = ({ private renderInteractiveSceneCallback = ({
atLeastOneVisibleElement, atLeastOneVisibleElement,