Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions app/client/src/entities/FeatureFlag.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
type FeatureFlag = {
COMMENT: boolean;
JS_EDITOR: boolean;
MULTIPLAYER: boolean;
};

export default FeatureFlag;
18 changes: 13 additions & 5 deletions app/client/src/pages/Editor/Canvas.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React, { memo, useCallback } from "react";
import store from "store";
import store, { useSelector } from "store";
import WidgetFactory from "utils/WidgetFactory";
import { RenderModes } from "constants/WidgetConstants";
import { ContainerWidgetProps } from "widgets/ContainerWidget";
Expand All @@ -17,6 +17,7 @@ import {
APP_COLLAB_EVENTS,
NAMESPACE_COLLAB_PAGE_EDIT,
} from "constants/AppCollabConstants";
import { isMultiplayerEnabledForUser as isMultiplayerEnabledForUserSelector } from "selectors/appCollabSelectors";

interface CanvasProps {
dsl: ContainerWidgetProps<WidgetProps>;
Expand Down Expand Up @@ -46,12 +47,16 @@ const shareMousePointer = (e: any, pageId: string) => {
// TODO(abhinav): get the render mode from context
const Canvas = memo((props: CanvasProps) => {
const { pageId } = props;
const isMultiplayerEnabledForUser = useSelector(
isMultiplayerEnabledForUserSelector,
);
const delayedShareMousePointer = useCallback(
throttle((e) => shareMousePointer(e, pageId), 50, {
trailing: false,
}),
[shareMousePointer, pageId],
);

try {
return (
<>
Expand All @@ -62,16 +67,19 @@ const Canvas = memo((props: CanvasProps) => {
id="art-board"
onMouseMove={(e) => {
e.persist();
if (!isMultiplayerEnabledForUser) return;
delayedShareMousePointer(e);
}}
width={props.dsl.rightColumn}
>
{props.dsl.widgetId &&
WidgetFactory.createWidget(props.dsl, RenderModes.CANVAS)}
<CanvasMultiPointerArena
pageEditSocket={pageEditSocket}
pageId={pageId}
/>
{isMultiplayerEnabledForUser && (
<CanvasMultiPointerArena
pageEditSocket={pageEditSocket}
pageId={pageId}
/>
)}
</ArtBoard>
</>
);
Expand Down
9 changes: 8 additions & 1 deletion app/client/src/pages/Editor/EditorHeader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ import { useLocation } from "react-router";
import { setIsGitSyncModalOpen } from "actions/gitSyncActions";
import RealtimeAppEditors from "./RealtimeAppEditors";
import { EditorSaveIndicator } from "./EditorSaveIndicator";
import { isMultiplayerEnabledForUser as isMultiplayerEnabledForUserSelector } from "selectors/appCollabSelectors";

const HeaderWrapper = styled(StyledHeader)`
width: 100%;
Expand Down Expand Up @@ -227,6 +228,10 @@ export function EditorHeader(props: EditorHeaderProps) {
dispatch(setIsGitSyncModalOpen(true));
}, [dispatch, setIsGitSyncModalOpen]);

const isMultiplayerEnabledForUser = useSelector(
isMultiplayerEnabledForUserSelector,
);

return (
<ThemeProvider theme={props.darkTheme}>
<HeaderWrapper>
Expand Down Expand Up @@ -276,7 +281,9 @@ export function EditorHeader(props: EditorHeaderProps) {
</HeaderSection>
<HeaderSection>
<EditorSaveIndicator />
<RealtimeAppEditors applicationId={applicationId} />
{isMultiplayerEnabledForUser && (
<RealtimeAppEditors applicationId={applicationId} />
)}
<Boxed step={OnboardingStep.FINISH}>
<FormDialogComponent
Form={AppInviteUsersForm}
Expand Down
34 changes: 26 additions & 8 deletions app/client/src/sagas/WebsocketSagas/WebsocketSagas.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,14 @@
import { io } from "socket.io-client";
import { eventChannel } from "redux-saga";
import { fork, take, call, cancel, put, delay } from "redux-saga/effects";
import {
fork,
take,
call,
cancel,
put,
delay,
select,
} from "redux-saga/effects";
import {
ReduxActionTypes,
ReduxSagaChannels,
Expand All @@ -17,6 +25,8 @@ import {
} from "actions/websocketActions";

import handleSocketEvent from "./handleSocketEvent";
import { isMultiplayerEnabledForUser } from "selectors/appCollabSelectors";
import { areCommentsEnabledForUserAndApp } from "selectors/commentsSelectors";

function connect() {
const socket = io();
Expand Down Expand Up @@ -85,6 +95,10 @@ function* handleIO(socket: any) {

function* flow() {
while (true) {
yield take([
ReduxActionTypes.FETCH_FEATURE_FLAGS_SUCCESS,
ReduxActionTypes.RETRY_WEBSOCKET_CONNECTION, // for manually triggering reconnection
]);
try {
/**
* Incase the socket is disconnected due to network latencies
Expand All @@ -93,13 +107,17 @@ function* flow() {
* We only need to retry incase the socket connection isn't made
* in the first attempt itself
*/
const socket = yield call(connect);
const task = yield fork(handleIO, socket);
yield put(setIsWebsocketConnected(true));
yield take([ReduxActionTypes.LOGOUT_USER_INIT]);
yield take();
yield cancel(task);
socket.disconnect();
const commentsEnabled = yield select(areCommentsEnabledForUserAndApp);
const multiplayerEnabled = yield select(isMultiplayerEnabledForUser);
if (commentsEnabled || multiplayerEnabled) {
const socket = yield call(connect);
const task = yield fork(handleIO, socket);
yield put(setIsWebsocketConnected(true));
yield take([ReduxActionTypes.LOGOUT_USER_INIT]);
yield take();
yield cancel(task);
socket.disconnect();
}
} catch (e) {
// this has to be non blocking
yield fork(function*() {
Expand Down
3 changes: 3 additions & 0 deletions app/client/src/selectors/appCollabSelectors.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { createSelector } from "reselect";
import { AppState } from "reducers";
import { AppCollabReducerState } from "reducers/uiReducers/appCollabReducer";
import { getCurrentUser } from "./usersSelectors";
import getFeatureFlags from "../utils/featureFlags";

export const getAppCollabState = (state: AppState) => state.ui.appCollab;

Expand All @@ -11,3 +12,5 @@ export const getRealtimeAppEditors = createSelector(
(appCollab: AppCollabReducerState, currentUser) =>
appCollab.editors.filter((el) => el.email !== currentUser?.email),
);

export const isMultiplayerEnabledForUser = () => getFeatureFlags().MULTIPLAYER;