fixes/multi-editor: users should be able to edit different version of the app at real time without sync

This commit is contained in:
arpitnath 2023-09-07 13:18:13 +05:30
parent 7fbeee7d7e
commit 77730b07ca
3 changed files with 30 additions and 20 deletions

View file

@ -125,6 +125,7 @@ const EditorComponent = (props) => {
appDefinitionDiff,
appDiffOptions,
events,
areOthersOnSameVersionAndPage,
} = useAppInfo();
const [currentPageId, setCurrentPageId] = useState(null);
@ -283,30 +284,32 @@ const EditorComponent = (props) => {
updateEditorState({
canUndo: false,
canRedo: false,
// currentVersion: uuid(),
});
};
/**
* When a new update is received over-the-websocket connection
* the useEffect in Container.jsx is triggered, but already appDef had been updated
* to avoid ymap observe going into a infinite loop a check is added where if the
* current appDef is equal to the newAppDef then we do not trigger a realtimeSave
* Initializes real-time saving of application definitions if multiplayer editing is enabled.
* Monitors changes in the 'appDef' property of the provided 'ymap' object and triggers a real-time save
* when all conditions are met.
*/
const initRealtimeSave = () => {
// Check if multiplayer editing is enabled; if not, return early
if (!config.ENABLE_MULTIPLAYER_EDITING) return null;
// Observe changes in the 'appDef' property of the 'ymap' object
props.ymap?.observe(() => {
const ymapUpdates = props.ymap?.get('appDef');
// Check if there is a new session and if others are on the same version and page
if (!ymapUpdates.currentSessionId || ymapUpdates.currentSessionId === currentSessionId) return;
// if (!isEqual(props.editingVersion?.id, props.ymap?.get('appDef').editingVersionId)) return;
if (isEqual(appDefinition, ymapUpdates.newDefinition)) return;
console.log('-----arpit real time ', {
x: ymapUpdates.currentSessionId,
y: currentSessionId,
});
// Check if others are on the same version and page
if (!ymapUpdates.areOthersOnSameVersionAndPage) return;
// Check if the new application definition is different from the current one
if (isEqual(appDefinition, ymapUpdates.newDefinition)) return;
// Trigger real-time save with specific options
realtimeSave(props.ymap?.get('appDef').newDefinition, {
skipAutoSave: true,
skipYmapUpdate: true,
@ -741,13 +744,6 @@ const EditorComponent = (props) => {
};
const appDefinitionChanged = async (newDefinition, opts = {}) => {
if (config.ENABLE_MULTIPLAYER_EDITING && !opts.skipYmapUpdate) {
props.ymap?.set('appDef', {
newDefinition,
editingVersionId: props.editingVersion?.id,
});
}
if (opts?.versionChanged) {
setCurrentPageId(newDefinition.homePageId);
@ -812,11 +808,12 @@ const EditorComponent = (props) => {
computeComponentState(updatedAppDefinition.pages[currentPageId]?.components);
}
if (!opts?.skipYmapUpdate && opts?.currentSessionId !== currentSessionId) {
if (config.ENABLE_MULTIPLAYER_EDITING && !opts?.skipYmapUpdate && opts?.currentSessionId !== currentSessionId) {
props.ymap?.set('appDef', {
newDefinition: updatedAppDefinition,
editingVersionId: props.editingVersion?.id,
currentSessionId,
areOthersOnSameVersionAndPage,
});
}
};

View file

@ -1,8 +1,9 @@
import React from 'react';
import React, { useEffect } from 'react';
import Popover from '@/_ui/Popover';
import Avatar from '@/_ui/Avatar';
// eslint-disable-next-line import/no-unresolved
import { useOthers, useSelf } from '@y-presence/react';
import { useAppDataActions, useAppInfo } from '@/_stores/appDataStore';
const MAX_DISPLAY_USERS = 2;
const RealtimeAvatars = ({ darkMode }) => {
@ -17,6 +18,17 @@ const RealtimeAvatars = ({ darkMode }) => {
const getAvatarText = (presence) => presence.firstName?.charAt(0) + presence.lastName?.charAt(0);
const getAvatarTitle = (presence) => `${presence.firstName} ${presence.lastName}`;
const { updateState } = useAppDataActions();
const { areOthersOnSameVersionAndPage, currentVersionId } = useAppInfo();
useEffect(() => {
const areActiveUsersOnSameVersionAndPage = othersOnSameVersionAndPage.length > 0;
const shouldUpdateState = areActiveUsersOnSameVersionAndPage !== areOthersOnSameVersionAndPage;
if (shouldUpdateState) updateState({ areOthersOnSameVersionAndPage: areActiveUsersOnSameVersionAndPage });
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [JSON.stringify({ others, self, currentVersionId })]);
const popoverContent = () => {
return othersOnSameVersionAndPage
.slice(MAX_DISPLAY_USERS, othersOnSameVersionAndPage.length)

View file

@ -22,6 +22,7 @@ const initialState = {
appDiffOptions: {},
isSaving: false,
appId: null,
areOthersOnSameVersionAndPage: false,
};
export const useAppDataStore = create(