Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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;
LINTING: boolean;
SNIPPET: boolean;
};
Expand Down
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;