Refactor: create component for walkthrough & ws (#2307)

* refactor: create component for walkthrough

* fix: lint

* refactor: move websocket to a different file

* close socket on unmount
This commit is contained in:
Gandharv 2022-02-21 23:07:48 +05:00 committed by GitHub
parent 2cc788ab6c
commit 3c0fa37a5f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 151 additions and 150 deletions

View file

@ -25,8 +25,6 @@ import {
setStateAsync,
computeComponentState,
getSvgIcon,
addToLocalStorage,
getDataFromLocalStorage,
} from '@/_helpers/appUtils';
import { Confirm } from './Viewer/Confirm';
import ReactTooltip from 'react-tooltip';
@ -45,9 +43,9 @@ import DesktopSelectedIcon from './Icons/desktop-selected.svg';
import Modal from 'react-bootstrap/Modal';
import Button from 'react-bootstrap/Button';
import { AppVersionsManager } from './AppVersionsManager';
import * as Driver from 'driver.js';
import 'driver.js/dist/driver.min.css';
import { SearchBoxComponent } from '@/_ui/Search';
import { initEditorWalkThrough } from '@/_helpers/createWalkThrough';
import { createWebsocketConnection } from '@/_helpers/websocketConnection';
setAutoFreeze(false);
enablePatches();
@ -58,8 +56,13 @@ class Editor extends React.Component {
const appId = this.props.match.params.id;
const currentUser = authenticationService.currentUserValue;
const { socket } = createWebsocketConnection(appId);
let userVars = {};
this.socket = socket;
if (currentUser) {
userVars = {
email: currentUser.email,
@ -114,7 +117,6 @@ class Editor extends React.Component {
isDeletingDataQuery: false,
showHiddenOptionsForDataQueryId: null,
showQueryConfirmation: false,
socket: null,
showInitVersionCreateModal: false,
isCreatingInitVersion: false,
initVersionName: 'v1',
@ -139,100 +141,12 @@ class Editor extends React.Component {
this.fetchApp();
this.initComponentVersioning();
this.initEventListeners();
config.COMMENT_FEATURE_ENABLE && this.initWebSocket();
this.setState({
currentSidebarTab: 2,
selectedComponent: null,
});
}
initWalkThrough() {
const driver = new Driver({
allowClose: true,
closeBtnText: 'Skip',
nextBtnText: 'Next',
prevBtnText: 'Previous',
padding: 2,
onReset: () => {
// Here we need to write the logic to update walkthroughCompleted column of the current user.
addToLocalStorage({ key: 'walkthroughCompleted', value: true });
},
className: `${this.props.darkMode ? 'dark-theme' : 'light-theme'}-walkthrough`,
});
if (
getDataFromLocalStorage('walkthroughCompleted') == undefined ||
!getDataFromLocalStorage('walkthroughCompleted')
) {
driver.defineSteps([
{
element: '.component-image-holder',
popover: {
title: 'Drag and drop widgets',
description: 'From the widget sidebar, drag and drop widgets to the canvas.',
position: 'left',
closeBtnText: 'Skip (1/6)',
},
},
{
element: '.sidebar-datasources',
popover: {
title: 'Connect to data sources',
description: 'You can manage your data sources from here.',
position: 'right',
closeBtnText: 'Skip (2/6)',
},
},
{
element: '.left-sidebar-inspector',
popover: {
title: 'Inspector',
description: 'Inspector lets you check the properties of widgets, results of queries etc.',
position: 'right',
closeBtnText: 'Skip (3/6)',
},
},
{
element: '.queries-header ',
popover: {
title: 'Create queries',
description:
'Create queries to interact with your data sources, run JavaScript snippets and to make API requests.',
position: 'top',
closeBtnText: 'Skip (4/6)',
},
},
{
element: '.release-buttons',
popover: {
title: 'Preview, release & share',
description:
'Click on preview to view the current changes on app viewer. Click on share button to view the sharing options. Release the editing version to make the changes live. Released versions cannot be modified, you will have to create another version to make more changes.',
position: 'bottom',
closeBtnText: 'Skip (5/6)',
},
},
{
element: '.sidebar-comments',
popover: {
title: 'Collaborate',
description: 'Add comments on canvas and tag your team members to collaborate.',
position: 'right',
closeBtnText: 'Skip (6/6)',
},
},
]);
driver.start();
}
}
componentDidUpdate(prevProps, prevState) {
if (prevState.editingVersion == undefined && this.state.editingVersion) {
this.initWalkThrough();
}
}
isVersionReleased = (version = this.state.editingVersion) => {
if (isEmpty(version)) {
return false;
@ -291,59 +205,10 @@ class Editor extends React.Component {
componentWillUnmount() {
document.removeEventListener('mousemove', this.onMouseMove);
document.removeEventListener('mouseup', this.onMouseUp);
if (this.state.socket) {
this.state.socket?.close();
}
document.title = 'Tooljet - Dashboard';
this.socket && this.socket?.close();
}
getWebsocketUrl = () => {
const re = /https?:\/\//g;
if (re.test(config.apiUrl)) return config.apiUrl.replace(/(^\w+:|^)\/\//, '').replace('/api', '');
return window.location.host;
};
initWebSocket = () => {
// TODO: add retry policy
const socket = new WebSocket(`${window.location.protocol === 'https:' ? 'wss' : 'ws'}://${this.getWebsocketUrl()}`);
const appId = this.props.match.params.id;
// Connection opened
socket.addEventListener('open', function (event) {
console.log('connection established', event);
const currentUser = JSON.parse(localStorage.getItem('currentUser'));
socket.send(
JSON.stringify({
event: 'authenticate',
data: currentUser.auth_token,
})
);
socket.send(
JSON.stringify({
event: 'subscribe',
data: appId,
})
);
});
// Connection closed
socket.addEventListener('close', function (event) {
console.log('connection closed', event);
});
// Listen for possible errors
socket.addEventListener('error', function (event) {
console.log('WebSocket error: ', event);
});
this.setState({
socket,
});
};
// 1. When we receive an undoable action we can always undo but cannot redo anymore.
// 2. Whenever you perform an undo you can always redo and keep doing undo as long as we have a patch for it.
// 3. Whenever you redo you can always undo and keep doing redo as long as we have a patch for it.
@ -912,12 +777,14 @@ class Editor extends React.Component {
</span>
);
};
handleKeyPress = (event) => {
if (event.key === 'Enter') {
// eslint-disable-next-line no-undef
this.createInitVersion();
}
};
createInitVersion = () => {
const newVersionName = this.state.initVersionName;
const appId = this.state.appId;
@ -925,10 +792,15 @@ class Editor extends React.Component {
if (!isEmpty(newVersionName?.trim())) {
this.setState({ isCreatingInitVersion: true });
appVersionService.create(appId, newVersionName).then(() => {
this.setState({
showInitVersionCreateModal: false,
isCreatingInitVersion: false,
});
this.setState(
{
showInitVersionCreateModal: false,
isCreatingInitVersion: false,
},
() => {
initEditorWalkThrough();
}
);
toast.success('Version Created');
this.fetchApp();
});
@ -961,7 +833,6 @@ class Editor extends React.Component {
enforceFocus={false}
animation={false}
centered={true}
// eslint-disable-next-line no-undef
>
<Modal.Header>
<Modal.Title>Create Version</Modal.Title>
@ -1211,7 +1082,7 @@ class Editor extends React.Component {
<>
<Container
canvasWidth={this.getCanvasWidth()}
socket={this.state.socket}
socket={this.socket}
showComments={showComments}
appVersionsId={this.state?.editingVersion?.id}
appDefinition={appDefinition}
@ -1445,7 +1316,7 @@ class Editor extends React.Component {
</div>
{config.COMMENT_FEATURE_ENABLE && showComments && (
<CommentNotifications
socket={this.state.socket}
socket={this.socket}
appVersionsId={this.state?.editingVersion?.id}
toggleComments={this.toggleComments}
/>

View file

@ -0,0 +1,85 @@
import * as Driver from 'driver.js';
import { addToLocalStorage, getDataFromLocalStorage } from '@/_helpers/appUtils';
import 'driver.js/dist/driver.min.css';
export const initEditorWalkThrough = () => {
if (
getDataFromLocalStorage('walkthroughCompleted') == undefined ||
!getDataFromLocalStorage('walkthroughCompleted')
) {
const darkMode = getDataFromLocalStorage('darkMode') === 'true';
const driver = new Driver({
allowClose: true,
closeBtnText: 'Skip',
nextBtnText: 'Next',
prevBtnText: 'Previous',
padding: 2,
onReset: () => {
// Here we need to write the logic to update walkthroughCompleted column of the current user.
addToLocalStorage({ key: 'walkthroughCompleted', value: true });
},
className: `${darkMode ? 'dark-theme' : 'light-theme'}-walkthrough`,
});
driver.defineSteps([
{
element: '.component-image-holder',
popover: {
title: 'Drag and drop widgets',
description: 'From the widget sidebar, drag and drop widgets to the canvas.',
position: 'left',
closeBtnText: 'Skip (1/6)',
},
},
{
element: '.sidebar-datasources',
popover: {
title: 'Connect to data sources',
description: 'You can manage your data sources from here.',
position: 'right',
closeBtnText: 'Skip (2/6)',
},
},
{
element: '.left-sidebar-inspector',
popover: {
title: 'Inspector',
description: 'Inspector lets you check the properties of widgets, results of queries etc.',
position: 'right',
closeBtnText: 'Skip (3/6)',
},
},
{
element: '.queries-header ',
popover: {
title: 'Create queries',
description:
'Create queries to interact with your data sources, run JavaScript snippets and to make API requests.',
position: 'top',
closeBtnText: 'Skip (4/6)',
},
},
{
element: '.release-buttons',
popover: {
title: 'Preview, release & share',
description:
'Click on preview to view the current changes on app viewer. Click on share button to view the sharing options. Release the editing version to make the changes live. Released versions cannot be modified, you will have to create another version to make more changes.',
position: 'bottom',
closeBtnText: 'Skip (5/6)',
},
},
{
element: '.sidebar-comments',
popover: {
title: 'Collaborate',
description: 'Add comments on canvas and tag your team members to collaborate.',
position: 'right',
closeBtnText: 'Skip (6/6)',
},
},
]);
driver.start();
}
};

View file

@ -0,0 +1,45 @@
import config from 'config';
class WebSocketConnection {
constructor(appId) {
this.socket = new WebSocket(`${window.location.protocol === 'https:' ? 'wss' : 'ws'}://${this.getWebsocketUrl()}`);
this.addListeners(appId);
}
getWebsocketUrl() {
const re = /https?:\/\//g;
if (re.test(config.apiUrl)) return config.apiUrl.replace(/(^\w+:|^)\/\//, '').replace('/api', '');
return window.location.host;
}
addListeners(appId) {
// Connection opened
this.socket.addEventListener('open', (event) => {
console.log('connection established', event);
const currentUser = JSON.parse(localStorage.getItem('currentUser'));
this.socket.send(
JSON.stringify({
event: 'authenticate',
data: currentUser.auth_token,
})
);
});
// Connection closed
this.socket.addEventListener('close', (event) => {
console.log('connection closed', event);
});
// Listen for possible errors
this.socket.addEventListener('error', (event) => {
console.log('WebSocket error: ', event);
});
}
}
export const createWebsocketConnection = (appId) => {
return new WebSocketConnection(appId);
};