* Initial scaffolding for comments CRUD APIs * add actions * add assets * state management for existing comments and creating new * add ui components * add overlay comments wrapper to baseWidget * add toggle comment mode button at editor header * trigger tests * Disallow commenting as someone else * Add applicationId for comments * lint * Add overlay blacklist to prevent component interaction while adding comments * Comment thread style updates * Placeholder comment context menu * Controlled comment thread visibility for making new comments visible by default * Update comment type description * Reset input on save * Resolve comment thread button ui * fix close on esc key, dont create new comment on outside click * Submit on enter * add emoji picker * Attempt at adding a websocket server in Java * CRUD APIs for comment threads * Add API for getting all threads in application * Move types to a separate file * Initial commit for real time server (RTS) * Add script to start RTS * Fix position property * Use create comment thread API * Use add comment to thread API * Add custom cursor * Dispatch logout init on 401 errors * Allow CORS for real time connection * Add more logs to RTS * Fix construction of MongoClient * WIP: Real time comments * Enable comments * Minor updates * Read backend API base URL from environment * Escape to reset comments mode * Set popover position as auto and boundary as scroll parent * Disable warning * Added permissions for comment threads * Add resolved API for comment threads * Migration to set commenting permission on existing apps * Fix updates bringing the RTS down * Show view latest button, scroll to bottom on creating a new comment * Cleanup comment reducer * Move to typescript for RTS * Add missing server.ts and tsconfig files * Resolve / unresolve comment * Scaffold app comments * Minor fixes: comment on top of all widgets, add toggle button at viewer header * Reconnect socket on creating a new app, set connected status in store * Retry socket connection flow * Integration tests for comments with api mocks using msw * Fix circular depependency * rm file * Minor cleanup and comments * Minor refactors: move isScrolledToBottom to common hooks, decouple prevent interactions overlay from comments wrapper * Use policies when pushing updates in RTS * ENV var to set if comments are enabled * Fix: check if editor/viewer is initialised before waiting for init action * Add tests for comments reducer * Revert "ENV var to set if comments are enabled" This reverts commit 988efeaa69d378d943a387e1e73510334958adc5. * Enable comments for users with appsmith email * lint * fix * Try running a socket.io server inside backend * Update comment reducer tests * Init mentions within comments * Fix comment thread updates with email rooms * Minor fixes * Refactors / review suggestions * lint * increase cache limit for builds * Comment out tests for feature that's under development * Add Dockerfile for RTS * Fix policies missing for first comment in threads * Use draftJS for comments input with mentions support * fix fixtures * Use thread's policies when querying for threads * Update socket.io to v4 * Add support for richer body with mentions * Update comment body type to RawDraftContentState * fix stale method * Fix mentions search * Minor cleanups * Comment context menu and thread UI updates * revert: Scaffold app comments * Yarn dependencies * Delete comment using id api added * Init app comments * Add test for creating thread * Api for delete comment with id * Test comment creation response and policies * Copy comment links * Fix reset editor state * Delete valid comment testcase added * Delete comment TC : code refactor * Don't allow creating comments with an empty body * Pin comments WIP[] * Ignore dependency-reduced-pom.xml files from VCS * Cleanup of some dev-only files, for review * Delete comment * Update socket.io to v4 in RTS * Pin and resolve comment thread object added in commentThread * Pin and resolve comment thread object added in commentThread * Update comment thread API * Added creationTime and updationTime in comment thread response * Added creationTime and updationTime in comment thread response * Added human readable id to comment threads, fallback to username for null name in user document * Refactor * lint * fix test, rm duplicate selector * comment out saga used for dev * CommentThread viewed status, username fallback for getName=null, username field added in pin & resolve status * lint * trigger tests Co-authored-by: Shrikant Sharat Kandula <shrikant@appsmith.com> Co-authored-by: Abhijeet <abhi.nagarnaik@gmail.com>
135 lines
3.3 KiB
TypeScript
135 lines
3.3 KiB
TypeScript
import { io } from "socket.io-client";
|
|
import { eventChannel } from "redux-saga";
|
|
import {
|
|
fork,
|
|
take,
|
|
call,
|
|
cancel,
|
|
put,
|
|
delay,
|
|
select,
|
|
} from "redux-saga/effects";
|
|
import {
|
|
ReduxActionTypes,
|
|
ReduxSagaChannels,
|
|
} from "constants/ReduxActionConstants";
|
|
import { ANONYMOUS_USERNAME } from "constants/userConstants";
|
|
import {
|
|
WEBSOCKET_EVENTS,
|
|
websocketDisconnectedEvent,
|
|
websocketConnectedEvent,
|
|
} from "constants/WebsocketConstants";
|
|
|
|
import { commentEvent } from "actions/commentActions";
|
|
import {
|
|
setIsWebsocketConnected,
|
|
retrySocketConnection,
|
|
} from "actions/websocketActions";
|
|
|
|
import { areCommentsEnabledForUser } from "selectors/commentsSelectors";
|
|
|
|
function connect() {
|
|
const socket = io();
|
|
|
|
return new Promise((resolve) => {
|
|
socket.on("connect", () => {
|
|
resolve(socket);
|
|
});
|
|
});
|
|
}
|
|
|
|
function subscribe(socket: any) {
|
|
return eventChannel((emit) => {
|
|
socket.onAny((event: any, ...args: any) => {
|
|
emit({
|
|
type: event,
|
|
payload: args,
|
|
});
|
|
});
|
|
socket.on("disconnect", () => {
|
|
emit(websocketDisconnectedEvent());
|
|
});
|
|
socket.on("connect", () => {
|
|
emit(websocketConnectedEvent());
|
|
});
|
|
return () => {
|
|
socket.disconnect();
|
|
};
|
|
});
|
|
}
|
|
|
|
function* read(socket: any) {
|
|
const channel = yield call(subscribe, socket);
|
|
while (true) {
|
|
const action = yield take(channel);
|
|
switch (action.type) {
|
|
case WEBSOCKET_EVENTS.DISCONNECTED:
|
|
yield put(setIsWebsocketConnected(false));
|
|
break;
|
|
case WEBSOCKET_EVENTS.CONNECTED:
|
|
yield put(setIsWebsocketConnected(true));
|
|
break;
|
|
default:
|
|
yield put(commentEvent(action));
|
|
}
|
|
}
|
|
}
|
|
|
|
function* write(socket: any) {
|
|
while (true) {
|
|
const { payload } = yield take(ReduxSagaChannels.WEBSOCKET_WRITE_CHANNEL);
|
|
// reconnect to reset connection at the server
|
|
if (payload.type === WEBSOCKET_EVENTS.RECONNECT) {
|
|
socket.disconnect().connect();
|
|
} else {
|
|
// handle other writes here:
|
|
// socket.emit(payload.type, payload.payload);
|
|
}
|
|
}
|
|
}
|
|
|
|
function* handleIO(socket: any) {
|
|
yield fork(read, socket);
|
|
yield fork(write, socket);
|
|
}
|
|
|
|
function* flow() {
|
|
while (true) {
|
|
const { payload } = yield take([
|
|
ReduxActionTypes.FETCH_USER_DETAILS_SUCCESS,
|
|
ReduxActionTypes.RETRY_WEBSOCKET_CONNECTION,
|
|
]);
|
|
|
|
try {
|
|
/**
|
|
* Incase the socket is disconnected due to network latencies
|
|
* it reuses the same instance so we don't need to bind it again
|
|
* this is verified using the reconnect flow
|
|
* We only need to retry incase the socket connection isn't made
|
|
* in the first attempt itself
|
|
*/
|
|
if (payload.name !== ANONYMOUS_USERNAME) {
|
|
const commentsEnabled = yield select(areCommentsEnabledForUser);
|
|
if (!commentsEnabled) return;
|
|
|
|
const socket = yield call(connect);
|
|
const task = yield fork(handleIO, socket);
|
|
yield put(setIsWebsocketConnected(true));
|
|
yield take(ReduxActionTypes.LOGOUT_USER_INIT);
|
|
yield cancel(task);
|
|
socket.disconnect();
|
|
}
|
|
} catch (e) {
|
|
// this has to be non blocking
|
|
yield fork(function*() {
|
|
yield delay(3000);
|
|
yield put(retrySocketConnection());
|
|
});
|
|
}
|
|
}
|
|
}
|
|
|
|
export default function* rootSaga() {
|
|
yield fork(flow);
|
|
}
|