diff --git a/README.md b/README.md
index 32421d883..dd248aea5 100644
--- a/README.md
+++ b/README.md
@@ -63,7 +63,7 @@ OpenReplay can be deployed anywhere. Follow our step-by-step guides for deployin
## OpenReplay Cloud
-For those who want to simply use OpenReplay as a service, [sign up](https://asayer.io/register.html) for a free account on our cloud offering.
+For those who want to simply use OpenReplay as a service, [sign up](https://app.openreplay.com/signup) for a free account on our cloud offering.
## Community Support
diff --git a/codeql-analysis.yml b/codeql-analysis.yml
new file mode 100644
index 000000000..a79a63767
--- /dev/null
+++ b/codeql-analysis.yml
@@ -0,0 +1,71 @@
+# For most projects, this workflow file will not need changing; you simply need
+# to commit it to your repository.
+#
+# You may wish to alter this file to override the set of languages analyzed,
+# or to provide custom queries or build logic.
+#
+# ******** NOTE ********
+# We have attempted to detect the languages in your repository. Please check
+# the `language` matrix defined below to confirm you have the correct set of
+# supported CodeQL languages.
+#
+name: "CodeQL"
+
+on:
+ push:
+ branches: [ dev ]
+ pull_request:
+ # The branches below must be a subset of the branches above
+ branches: [ dev ]
+ schedule:
+ - cron: '30 23 * * 6'
+
+jobs:
+ analyze:
+ name: Analyze
+ runs-on: ubuntu-latest
+ permissions:
+ actions: read
+ contents: read
+ security-events: write
+
+ strategy:
+ fail-fast: false
+ matrix:
+ language: [ 'go', 'javascript', 'python' ]
+ # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ]
+ # Learn more:
+ # https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#changing-the-languages-that-are-analyzed
+
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@v2
+
+ # Initializes the CodeQL tools for scanning.
+ - name: Initialize CodeQL
+ uses: github/codeql-action/init@v1
+ with:
+ languages: ${{ matrix.language }}
+ # If you wish to specify custom queries, you can do so here or in a config file.
+ # By default, queries listed here will override any specified in a config file.
+ # Prefix the list here with "+" to use these queries and those in the config file.
+ # queries: ./path/to/local/query, your-org/your-repo/queries@main
+
+ # Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
+ # If this step fails, then you should remove it and run the build manually (see below)
+ - name: Autobuild
+ uses: github/codeql-action/autobuild@v1
+
+ # âšī¸ Command-line programs to run using the OS shell.
+ # đ https://git.io/JvXDl
+
+ # âī¸ If the Autobuild fails above, remove it and uncomment the following three lines
+ # and modify them (or add more) to build your code if your project
+ # uses a compiled language
+
+ #- run: |
+ # make bootstrap
+ # make release
+
+ - name: Perform CodeQL Analysis
+ uses: github/codeql-action/analyze@v1
diff --git a/frontend/app/components/BugFinder/BugFinder.js b/frontend/app/components/BugFinder/BugFinder.js
index 3aa234b26..bac9ea8e6 100644
--- a/frontend/app/components/BugFinder/BugFinder.js
+++ b/frontend/app/components/BugFinder/BugFinder.js
@@ -25,10 +25,9 @@ import { LAST_7_DAYS } from 'Types/app/period';
import { resetFunnel } from 'Duck/funnels';
import { resetFunnelFilters } from 'Duck/funnelFilters'
import NoSessionsMessage from '../shared/NoSessionsMessage';
+import TrackerUpdateMessage from '../shared/TrackerUpdateMessage';
import LiveSessionList from './LiveSessionList'
-const AUTOREFRESH_INTERVAL = 10 * 60 * 1000;
-
const weakEqual = (val1, val2) => {
if (!!val1 === false && !!val2 === false) return true;
if (!val1 !== !val2) return false;
@@ -37,7 +36,6 @@ const weakEqual = (val1, val2) => {
@withLocationHandlers()
@connect(state => ({
- shouldAutorefresh: state.getIn([ 'filters', 'appliedFilter', 'events' ]).size === 0,
filter: state.getIn([ 'filters', 'appliedFilter' ]),
showLive: state.getIn([ 'user', 'account', 'appearance', 'sessionsLive' ]),
variables: state.getIn([ 'customFields', 'list' ]),
@@ -93,12 +91,6 @@ export default class BugFinder extends React.PureComponent {
this.props.resetFunnel();
this.props.resetFunnelFilters();
- this.autorefreshIntervalId = setInterval(() => {
- if (this.props.shouldAutorefresh) {
- props.applyFilter();
- }
- }, AUTOREFRESH_INTERVAL);
-
props.fetchFunnelsList(LAST_7_DAYS)
}
@@ -129,10 +121,6 @@ export default class BugFinder extends React.PureComponent {
}.bind(this));
}
- componentWillUnmount() {
- clearInterval(this.autorefreshIntervalId);
- }
-
setActiveTab = tab => {
this.props.setActiveTab(tab);
}
@@ -151,6 +139,7 @@ export default class BugFinder extends React.PureComponent {
/>
+
,
fetchList: (params) => void,
+ applyFilter: () => void,
filters: List
}
function LiveSessionList(props: Props) {
const { loading, list, filters } = props;
+ var timeoutId;
useEffect(() => {
props.fetchList(filters.toJS());
+ timeout();
+ return () => {
+ clearTimeout(timeoutId)
+ }
}, [])
+ const timeout = () => {
+ timeoutId = setTimeout(() => {
+ props.fetchList(filters.toJS());
+ timeout();
+ }, AUTOREFRESH_INTERVAL);
+ }
+
return (
+ See how to {'enable Assist'} if you haven't yet done so.
+
+ }
image={
}
show={ !loading && list && list.size === 0}
>
diff --git a/frontend/app/components/BugFinder/SessionList/SessionList.js b/frontend/app/components/BugFinder/SessionList/SessionList.js
index 41375a6af..0aa4b9afb 100644
--- a/frontend/app/components/BugFinder/SessionList/SessionList.js
+++ b/frontend/app/components/BugFinder/SessionList/SessionList.js
@@ -4,12 +4,14 @@ import { applyFilter, addAttribute, addEvent } from 'Duck/filters';
import SessionItem from 'Shared/SessionItem';
import SessionListHeader from './SessionListHeader';
import { KEYS } from 'Types/filter/customFilter';
-import styles from './sessionList.css';
const ALL = 'all';
const PER_PAGE = 10;
+const AUTOREFRESH_INTERVAL = 3 * 60 * 1000;
+var timeoutId;
@connect(state => ({
+ shouldAutorefresh: state.getIn([ 'filters', 'appliedFilter', 'events' ]).size === 0,
savedFilters: state.getIn([ 'filters', 'list' ]),
loading: state.getIn([ 'sessions', 'loading' ]),
activeTab: state.getIn([ 'sessions', 'activeTab' ]),
@@ -27,6 +29,7 @@ export default class SessionList extends React.PureComponent {
}
constructor(props) {
super(props);
+ this.timeout();
}
componentDidUpdate(prevProps) {
@@ -47,6 +50,15 @@ export default class SessionList extends React.PureComponent {
this.props.applyFilter()
}
+ timeout = () => {
+ timeoutId = setTimeout(function () {
+ if (this.props.shouldAutorefresh) {
+ this.props.applyFilter();
+ }
+ this.timeout();
+ }.bind(this), AUTOREFRESH_INTERVAL);
+ }
+
getNoContentMessage = activeTab => {
let str = "No recordings found";
if (activeTab.type !== 'all') {
@@ -57,6 +69,10 @@ export default class SessionList extends React.PureComponent {
return str + '!';
}
+ componentWillUnmount() {
+ clearTimeout(timeoutId)
+ }
+
renderActiveTabContent(list) {
const {
loading,
diff --git a/frontend/app/components/BugFinder/SessionsMenu/SessionsMenu.js b/frontend/app/components/BugFinder/SessionsMenu/SessionsMenu.js
index 129862b29..48cb9c0f8 100644
--- a/frontend/app/components/BugFinder/SessionsMenu/SessionsMenu.js
+++ b/frontend/app/components/BugFinder/SessionsMenu/SessionsMenu.js
@@ -7,6 +7,7 @@ import { fetchWatchdogStatus } from 'Duck/watchdogs';
import { setActiveFlow, clearEvents } from 'Duck/filters';
import { setActiveTab } from 'Duck/sessions';
import { issues_types } from 'Types/session/issue'
+import NewBadge from 'Shared/NewBadge';
function SessionsMenu(props) {
const {
@@ -75,11 +76,15 @@ function SessionsMenu(props) {
}
iconName="person"
active={activeTab.type === 'live'}
onClick={() => onMenuItemClick({ name: 'Assist', type: 'live' })}
/>
+
diff --git a/frontend/app/components/Client/Integrations/AssistDoc/AssistDoc.js b/frontend/app/components/Client/Integrations/AssistDoc/AssistDoc.js
index 01d3e7ad2..a0aef3cad 100644
--- a/frontend/app/components/Client/Integrations/AssistDoc/AssistDoc.js
+++ b/frontend/app/components/Client/Integrations/AssistDoc/AssistDoc.js
@@ -1,60 +1,53 @@
import Highlight from 'react-highlight'
import ToggleContent from 'Shared/ToggleContent'
import DocLink from 'Shared/DocLink/DocLink';
+import AssistScript from './AssistScript'
+import AssistNpm from './AssistNpm'
+import { Tabs } from 'UI';
+import { useState } from 'react';
+
+const NPM = 'NPM'
+const SCRIPT = 'SCRIPT'
+const TABS = [
+ { key: SCRIPT, text: SCRIPT },
+ { key: NPM, text: NPM },
+]
const AssistDoc = (props) => {
+ const { projectKey } = props;
+ const [activeTab, setActiveTab] = useState(SCRIPT)
+
+
+ const renderActiveTab = () => {
+ switch (activeTab) {
+ case SCRIPT:
+ return
+ case NPM:
+ return
+ }
+ return null;
+ }
+
+
return (
OpenReplay Assist allows you to support your users by seeing their live screen and instantly hopping on call (WebRTC) with them without requiring any 3rd-party screen sharing software.
-
+
Installation
{`npm i @openreplay/tracker-assist`}
-
-
Usage
-
Initialize the tracker then load the @openreplay/tracker-assist plugin.
-
+
Usage
-
- {`import Tracker from '@openreplay/tracker';
-import trackerAssist from '@openreplay/tracker-assist';
-const tracker = new Tracker({
- projectKey: PROJECT_KEY,
-});
-tracker.start();
-tracker.use(trackerAssist(options)); // check the list of available options below`}
-
- }
- second={
-
- {`import OpenReplay from '@openreplay/tracker/cjs';
-import trackerFetch from '@openreplay/tracker-assist/cjs';
-const tracker = new OpenReplay({
- projectKey: PROJECT_KEY
-});
-const trackerAssist = tracker.use(trackerAssist(options)); // check the list of available options below
-//...
-function MyApp() {
- useEffect(() => { // use componentDidMount in case of React Class Component
- tracker.start();
- }, [])
-//...
-}`}
-
- }
+ setActiveTab(tab) }
/>
- Options
-
- {`trackerAssist({
- confirmText: string;
-})`}
-
+
+ { renderActiveTab() }
+
diff --git a/frontend/app/components/Client/Integrations/AssistDoc/AssistNpm.tsx b/frontend/app/components/Client/Integrations/AssistDoc/AssistNpm.tsx
new file mode 100644
index 000000000..28c12bd30
--- /dev/null
+++ b/frontend/app/components/Client/Integrations/AssistDoc/AssistNpm.tsx
@@ -0,0 +1,53 @@
+import React from 'react';
+import Highlight from 'react-highlight'
+import ToggleContent from 'Shared/ToggleContent'
+
+function AssistNpm(props) {
+ return (
+
+
Initialize the tracker then load the @openreplay/tracker-assist plugin.
+
+
Usage
+
+ {`import Tracker from '@openreplay/tracker';
+import trackerAssist from '@openreplay/tracker-assist';
+const tracker = new Tracker({
+ projectKey: '${props.projectKey}',
+});
+tracker.start();
+tracker.use(trackerAssist(options)); // check the list of available options below`}
+
+ }
+ second={
+
+ {`import OpenReplay from '@openreplay/tracker/cjs';
+import trackerFetch from '@openreplay/tracker-assist/cjs';
+const tracker = new OpenReplay({
+ projectKey: '${props.projectKey}'
+});
+const trackerAssist = tracker.use(trackerAssist(options)); // check the list of available options below
+//...
+function MyApp() {
+ useEffect(() => { // use componentDidMount in case of React Class Component
+ tracker.start();
+ }, [])
+//...
+}`}
+
+ }
+ />
+
+ Options
+
+ {`trackerAssist({
+ confirmText: string;
+})`}
+
+
+ );
+}
+
+export default AssistNpm;
\ No newline at end of file
diff --git a/frontend/app/components/Client/Integrations/AssistDoc/AssistScript.tsx b/frontend/app/components/Client/Integrations/AssistDoc/AssistScript.tsx
new file mode 100644
index 000000000..932926a1a
--- /dev/null
+++ b/frontend/app/components/Client/Integrations/AssistDoc/AssistScript.tsx
@@ -0,0 +1,33 @@
+import React from 'react';
+import Highlight from 'react-highlight'
+
+function AssistScript(props) {
+ return (
+
+
If your OpenReplay tracker is set up using the JS snippet, then simply replace the .../openreplay.js occurrence with .../openreplay-assist.js. Below is an example of how the script should like after the change:
+
+
+
+ {`
+`}
+
+
+ );
+}
+
+export default AssistScript;
\ No newline at end of file
diff --git a/frontend/app/components/Client/Integrations/FetchDoc/FetchDoc.js b/frontend/app/components/Client/Integrations/FetchDoc/FetchDoc.js
index d8238c21f..8ba8e590d 100644
--- a/frontend/app/components/Client/Integrations/FetchDoc/FetchDoc.js
+++ b/frontend/app/components/Client/Integrations/FetchDoc/FetchDoc.js
@@ -3,6 +3,7 @@ import ToggleContent from 'Shared/ToggleContent'
import DocLink from 'Shared/DocLink/DocLink';
const FetchDoc = (props) => {
+ const { projectKey } = props;
return (
This plugin allows you to capture fetch payloads and inspect them later on while replaying session recordings. This is very useful for understanding and fixing issues.
@@ -18,14 +19,14 @@ const FetchDoc = (props) => {
Usage
{`import tracker from '@openreplay/tracker';
import trackerFetch from '@openreplay/tracker-fetch';
//...
const tracker = new OpenReplay({
- projectKey: PROJECT_KEY
+ projectKey: '${projectKey}'
});
tracker.start();
//...
@@ -40,7 +41,7 @@ fetch('https://api.openreplay.com/').then(response => console.log(response.json(
import trackerFetch from '@openreplay/tracker-fetch/cjs';
//...
const tracker = new OpenReplay({
- projectKey: PROJECT_KEY
+ projectKey: '${projectKey}'
});
//...
function SomeFunctionalComponent() {
diff --git a/frontend/app/components/Client/Integrations/GraphQLDoc/GraphQLDoc.js b/frontend/app/components/Client/Integrations/GraphQLDoc/GraphQLDoc.js
index b1b648f99..7a964de3a 100644
--- a/frontend/app/components/Client/Integrations/GraphQLDoc/GraphQLDoc.js
+++ b/frontend/app/components/Client/Integrations/GraphQLDoc/GraphQLDoc.js
@@ -3,6 +3,7 @@ import DocLink from 'Shared/DocLink/DocLink';
import ToggleContent from 'Shared/ToggleContent';
const GraphQLDoc = (props) => {
+ const { projectKey } = props;
return (
This plugin allows you to capture GraphQL requests and inspect them later on while replaying session recordings. This is very useful for understanding and fixing issues.
@@ -19,14 +20,14 @@ const GraphQLDoc = (props) => {
{`import OpenReplay from '@openreplay/tracker';
import trackerGraphQL from '@openreplay/tracker-graphql';
//...
const tracker = new OpenReplay({
- projectKey: PROJECT_KEY,
+ projectKey: '${projectKey}'
});
tracker.start();
//...
@@ -39,7 +40,7 @@ export const recordGraphQL = tracker.use(trackerGraphQL());`}
import trackerGraphQL from '@openreplay/tracker-graphql/cjs';
//...
const tracker = new OpenReplay({
- projectKey: PROJECT_KEY
+ projectKey: '${projectKey}'
});
//...
function SomeFunctionalComponent() {
diff --git a/frontend/app/components/Client/Integrations/Integrations.js b/frontend/app/components/Client/Integrations/Integrations.js
index 05036788e..f34050055 100644
--- a/frontend/app/components/Client/Integrations/Integrations.js
+++ b/frontend/app/components/Client/Integrations/Integrations.js
@@ -75,7 +75,7 @@ const TITLE = {
[ ASSIST ] : 'Assist',
}
-const DOCS = [REDUX, VUE, GRAPHQL, NGRX, FETCH, MOBX, PROFILER]
+const DOCS = [REDUX, VUE, GRAPHQL, NGRX, FETCH, MOBX, PROFILER, ASSIST]
const integrations = [ 'sentry', 'datadog', 'stackdriver', 'rollbar', 'newrelic', 'bugsnag', 'cloudwatch', 'elasticsearch', 'sumologic', 'issues' ];
@@ -87,12 +87,14 @@ const integrations = [ 'sentry', 'datadog', 'stackdriver', 'rollbar', 'newrelic'
state.getIn([ name, 'list' ]).size > 0;
props.loading = props.loading || state.getIn([ name, 'fetchRequest', 'loading']);
})
+ const site = state.getIn([ 'site', 'instance' ]);
return {
...props,
issues: state.getIn([ 'issues', 'list']).first() || {},
slackChannelListExists: state.getIn([ 'slack', 'list' ]).size > 0,
tenantId: state.getIn([ 'user', 'client', 'tenantId' ]),
- jwt: state.get('jwt')
+ jwt: state.get('jwt'),
+ projectKey: site ? site.projectKey : ''
};
}, {
fetchList,
@@ -142,7 +144,9 @@ export default class Integrations extends React.PureComponent {
}
}
- renderModalContent() {
+ renderModalContent() {
+ const { projectKey } = this.props;
+
switch (this.state.modalContent) {
case SENTRY:
return ;
@@ -172,21 +176,21 @@ export default class Integrations extends React.PureComponent {
case JIRA:
return ;
case REDUX:
- return
+ return
case VUE:
- return
+ return
case GRAPHQL:
- return
+ return
case NGRX:
- return
+ return
case FETCH:
- return
+ return
case MOBX:
- return
+ return
case PROFILER:
- return
+ return
case ASSIST:
- return
+ return
default:
return null;
}
diff --git a/frontend/app/components/Client/Integrations/MobxDoc/MobxDoc.js b/frontend/app/components/Client/Integrations/MobxDoc/MobxDoc.js
index 7c4b3233b..79166da56 100644
--- a/frontend/app/components/Client/Integrations/MobxDoc/MobxDoc.js
+++ b/frontend/app/components/Client/Integrations/MobxDoc/MobxDoc.js
@@ -3,6 +3,7 @@ import ToggleContent from 'Shared/ToggleContent'
import DocLink from 'Shared/DocLink/DocLink';
const MobxDoc = (props) => {
+ const { projectKey } = props;
return (
This plugin allows you to capture MobX events and inspect them later on while replaying session recordings. This is very useful for understanding and fixing issues.
@@ -18,14 +19,14 @@ const MobxDoc = (props) => {
Usage
{`import OpenReplay from '@openreplay/tracker';
import trackerMobX from '@openreplay/tracker-mobx';
//...
const tracker = new OpenReplay({
- projectKey: PROJECT_KEY
+ projectKey: '${projectKey}'
});
tracker.use(trackerMobX()); // check list of available options below
tracker.start();`}
@@ -37,7 +38,7 @@ tracker.start();`}
import trackerMobX from '@openreplay/tracker-mobx/cjs';
//...
const tracker = new OpenReplay({
- projectKey: PROJECT_KEY
+ projectKey: '${projectKey}'
});
tracker.use(trackerMobX()); // check list of available options below
//...
diff --git a/frontend/app/components/Client/Integrations/NgRxDoc/NgRxDoc.js b/frontend/app/components/Client/Integrations/NgRxDoc/NgRxDoc.js
index 092e93a7d..9aa441c7e 100644
--- a/frontend/app/components/Client/Integrations/NgRxDoc/NgRxDoc.js
+++ b/frontend/app/components/Client/Integrations/NgRxDoc/NgRxDoc.js
@@ -3,6 +3,7 @@ import ToggleContent from 'Shared/ToggleContent'
import DocLink from 'Shared/DocLink/DocLink';
const NgRxDoc = (props) => {
+ const { projectKey } = props;
return (
This plugin allows you to capture NgRx actions/state and inspect them later on while replaying session recordings. This is very useful for understanding and fixing issues.
@@ -18,7 +19,7 @@ const NgRxDoc = (props) => {
Usage
{`import { StoreModule } from '@ngrx/store';
@@ -27,7 +28,7 @@ import OpenReplay from '@openreplay/tracker';
import trackerNgRx from '@openreplay/tracker-ngrx';
//...
const tracker = new OpenReplay({
- projectKey: PROJECT_KEY
+ projectKey: '${projectKey}'
});
tracker.start();
//...
@@ -47,7 +48,7 @@ import OpenReplay from '@openreplay/tracker/cjs';
import trackerNgRx from '@openreplay/tracker-ngrx/cjs';
//...
const tracker = new OpenReplay({
- projectKey: PROJECT_KEY
+ projectKey: '${projectKey}'
});
//...
function SomeFunctionalComponent() {
diff --git a/frontend/app/components/Client/Integrations/ProfilerDoc/ProfilerDoc.js b/frontend/app/components/Client/Integrations/ProfilerDoc/ProfilerDoc.js
index e61f968b9..f00b98815 100644
--- a/frontend/app/components/Client/Integrations/ProfilerDoc/ProfilerDoc.js
+++ b/frontend/app/components/Client/Integrations/ProfilerDoc/ProfilerDoc.js
@@ -3,6 +3,7 @@ import ToggleContent from 'Shared/ToggleContent'
import DocLink from 'Shared/DocLink/DocLink';
const ProfilerDoc = (props) => {
+ const { projectKey } = props;
return (
The profiler plugin allows you to measure your JS functions' performance and capture both arguments and result for each function call.
@@ -18,14 +19,14 @@ const ProfilerDoc = (props) => {
Usage
{`import OpenReplay from '@openreplay/tracker';
import trackerProfiler from '@openreplay/tracker-profiler';
//...
const tracker = new OpenReplay({
- projectKey: PROJECT_KEY
+ projectKey: '${projectKey}'
});
tracker.start();
//...
@@ -42,7 +43,7 @@ const fn = profiler('call_name')(() => {
import trackerProfiler from '@openreplay/tracker-profiler/cjs';
//...
const tracker = new OpenReplay({
- projectKey: PROJECT_KEY
+ projectKey: '${projectKey}'
});
//...
function SomeFunctionalComponent() {
diff --git a/frontend/app/components/Client/Integrations/ReduxDoc/ReduxDoc.js b/frontend/app/components/Client/Integrations/ReduxDoc/ReduxDoc.js
index acc083a97..c4fa51240 100644
--- a/frontend/app/components/Client/Integrations/ReduxDoc/ReduxDoc.js
+++ b/frontend/app/components/Client/Integrations/ReduxDoc/ReduxDoc.js
@@ -3,6 +3,7 @@ import ToggleContent from '../../../shared/ToggleContent';
import DocLink from 'Shared/DocLink/DocLink';
const ReduxDoc = (props) => {
+ const { projectKey } = props;
return (
This plugin allows you to capture Redux actions/state and inspect them later on while replaying session recordings. This is very useful for understanding and fixing issues.
@@ -17,7 +18,7 @@ const ReduxDoc = (props) => {
Initialize the tracker then put the generated middleware into your Redux chain.
{`import { applyMiddleware, createStore } from 'redux';
@@ -25,7 +26,7 @@ import OpenReplay from '@openreplay/tracker';
import trackerRedux from '@openreplay/tracker-redux';
//...
const tracker = new OpenReplay({
- projectKey: PROJECT_KEY
+ projectKey: '${projectKey}'
});
tracker.start();
//...
@@ -42,7 +43,7 @@ import OpenReplay from '@openreplay/tracker/cjs';
import trackerRedux from '@openreplay/tracker-redux/cjs';
//...
const tracker = new OpenReplay({
- projectKey: PROJECT_KEY
+ projectKey: '${projectKey}'
});
//...
function SomeFunctionalComponent() {
diff --git a/frontend/app/components/Client/Integrations/VueDoc/VueDoc.js b/frontend/app/components/Client/Integrations/VueDoc/VueDoc.js
index 14a7e435a..b6682411c 100644
--- a/frontend/app/components/Client/Integrations/VueDoc/VueDoc.js
+++ b/frontend/app/components/Client/Integrations/VueDoc/VueDoc.js
@@ -3,6 +3,7 @@ import ToggleContent from '../../../shared/ToggleContent';
import DocLink from 'Shared/DocLink/DocLink';
const VueDoc = (props) => {
+ const { projectKey } = props;
return (
This plugin allows you to capture VueX mutations/state and inspect them later on while replaying session recordings. This is very useful for understanding and fixing issues.
@@ -18,7 +19,7 @@ const VueDoc = (props) => {
{`import Vuex from 'vuex'
@@ -26,7 +27,7 @@ import OpenReplay from '@openreplay/tracker';
import trackerVuex from '@openreplay/tracker-vuex';
//...
const tracker = new OpenReplay({
- projectKey: PROJECT_KEY
+ projectKey: '${projectKey}'
});
tracker.start();
//...
@@ -43,7 +44,7 @@ import OpenReplay from '@openreplay/tracker/cjs';
import trackerVuex from '@openreplay/tracker-vuex/cjs';
//...
const tracker = new OpenReplay({
- projectKey: PROJECT_KEY
+ projectKey: '${projectKey}'
});
//...
function SomeFunctionalComponent() {
diff --git a/frontend/app/components/Client/ManageUsers/ManageUsers.js b/frontend/app/components/Client/ManageUsers/ManageUsers.js
index 6d291ed1d..0d49d5319 100644
--- a/frontend/app/components/Client/ManageUsers/ManageUsers.js
+++ b/frontend/app/components/Client/ManageUsers/ManageUsers.js
@@ -27,7 +27,7 @@ const LIMIT_WARNING = 'You have reached users limit.';
fetchList,
generateInviteLink
})
-@withPageTitle('Manage Users - OpenReplay Preferences')
+@withPageTitle('Users - OpenReplay Preferences')
class ManageUsers extends React.PureComponent {
state = { showModal: false, remaining: this.props.account.limits.teamMember.remaining, invited: false }
@@ -50,7 +50,7 @@ class ManageUsers extends React.PureComponent {
deleteHandler = async (user) => {
if (await confirm({
- header: 'Manage Users',
+ header: 'Users',
confirmation: `Are you sure you want to remove this user?`
})) {
this.props.deleteMember(user.id).then(() => {
diff --git a/frontend/app/components/Client/PreferencesMenu/PreferencesMenu.js b/frontend/app/components/Client/PreferencesMenu/PreferencesMenu.js
index f2a59dd15..4a1ff3f1d 100644
--- a/frontend/app/components/Client/PreferencesMenu/PreferencesMenu.js
+++ b/frontend/app/components/Client/PreferencesMenu/PreferencesMenu.js
@@ -72,7 +72,7 @@ function PreferencesMenu({ activeTab, appearance, history }) {
setTab(CLIENT_TABS.MANAGE_USERS) }
/>
diff --git a/frontend/app/components/Client/Sites/NewSiteForm.js b/frontend/app/components/Client/Sites/NewSiteForm.js
index a9306048c..011ed8b01 100644
--- a/frontend/app/components/Client/Sites/NewSiteForm.js
+++ b/frontend/app/components/Client/Sites/NewSiteForm.js
@@ -2,6 +2,7 @@ import { connect } from 'react-redux';
import { Input, Button, Label } from 'UI';
import { save, edit, update , fetchList } from 'Duck/site';
import { pushNewSite, setSiteId } from 'Duck/user';
+import { withRouter } from 'react-router-dom';
import styles from './siteForm.css';
@connect(state => ({
@@ -17,6 +18,7 @@ import styles from './siteForm.css';
fetchList,
setSiteId
})
+@withRouter
export default class NewSiteForm extends React.PureComponent {
state = {
existsError: false,
@@ -24,7 +26,7 @@ export default class NewSiteForm extends React.PureComponent {
onSubmit = e => {
e.preventDefault();
- const { site, siteList } = this.props;
+ const { site, siteList, location: { pathname } } = this.props;
if (!site.exists() && siteList.some(({ name }) => name === site.name)) {
return this.setState({ existsError: true });
}
@@ -39,20 +41,21 @@ export default class NewSiteForm extends React.PureComponent {
const site = sites.last();
this.props.pushNewSite(site)
- this.props.setSiteId(site.id)
+ if (!pathname.includes('/client')) {
+ this.props.setSiteId(site.id)
+ }
this.props.onClose(null, site)
});
}
}
edit = ({ target: { name, value } }) => {
- if (value.includes(' ')) return; // TODO: site validation
this.setState({ existsError: false });
this.props.edit({ [ name ]: value });
}
render() {
- const { site, loading, onClose } = this.props;
+ const { site, loading } = this.props;
return (
diff --git a/frontend/app/components/Session_/Player/Controls/Controls.js b/frontend/app/components/Session_/Player/Controls/Controls.js
index 848e17153..266cf1cd1 100644
--- a/frontend/app/components/Session_/Player/Controls/Controls.js
+++ b/frontend/app/components/Session_/Player/Controls/Controls.js
@@ -399,7 +399,7 @@ export default class Controls extends React.Component {
icon="tachometer-slow"
/>
}
- { !live && showLongtasks &&
+ {/* { !live && showLongtasks &&
toggleBottomBlock(LONGTASKS) }
@@ -407,7 +407,7 @@ export default class Controls extends React.Component {
label="Long Tasks"
icon="business-time"
/>
- }
+ } */}
{ !live &&
diff --git a/frontend/app/components/Signup/SignupForm/SignupForm.js b/frontend/app/components/Signup/SignupForm/SignupForm.js
index 7df2822ee..c12c3dcc8 100644
--- a/frontend/app/components/Signup/SignupForm/SignupForm.js
+++ b/frontend/app/components/Signup/SignupForm/SignupForm.js
@@ -26,11 +26,24 @@ export default class SignupForm extends React.Component {
email: '',
projectName: '',
organizationName: '',
+ reload: false,
};
+ static getDerivedStateFromProps(props, state) {
+ if (props.errors && props.errors.size > 0 && state.reload) {
+ recaptchaRef.current.reset();
+ return {
+ reload: false
+ }
+ }
+ return null;
+ }
+
+
handleSubmit = (token) => {
const { tenantId, fullname, password, email, projectName, organizationName, auth } = this.state;
this.props.signup({ tenantId, fullname, password, email, projectName, organizationName, auth, 'g-recaptcha-response': token })
+ this.setState({ reload: true })
}
write = ({ target: { value, name } }) => this.setState({ [ name ]: value })
diff --git a/frontend/app/components/shared/TrackerUpdateMessage/TrackerUpdateMessage.js b/frontend/app/components/shared/TrackerUpdateMessage/TrackerUpdateMessage.js
new file mode 100644
index 000000000..985d1c5fc
--- /dev/null
+++ b/frontend/app/components/shared/TrackerUpdateMessage/TrackerUpdateMessage.js
@@ -0,0 +1,40 @@
+import React from 'react'
+import { Icon } from 'UI'
+import { connect } from 'react-redux'
+import { withRouter } from 'react-router-dom';
+import { onboarding as onboardingRoute } from 'App/routes'
+import { withSiteId } from 'App/routes';
+
+const TrackerUpdateMessage= (props) => {
+ // const { site } = props;
+ const { site, sites, match: { params: { siteId } } } = props;
+ const activeSite = sites.find(s => s.id == siteId);
+ const hasSessions = !!activeSite && !activeSite.recorded;
+ const needUpdate = !hasSessions && site.trackerVersion !== window.ENV.TRACKER_VERSION;
+ return needUpdate ? (
+ <>
+ {(
+
+ )}
+ >
+ ) : ''
+}
+
+export default connect(state => ({
+ site: state.getIn([ 'site', 'instance' ]),
+ sites: state.getIn([ 'site', 'list' ])
+}))(withRouter(TrackerUpdateMessage))
\ No newline at end of file
diff --git a/frontend/app/components/shared/TrackerUpdateMessage/index.js b/frontend/app/components/shared/TrackerUpdateMessage/index.js
new file mode 100644
index 000000000..b9f95895d
--- /dev/null
+++ b/frontend/app/components/shared/TrackerUpdateMessage/index.js
@@ -0,0 +1 @@
+export { default } from './TrackerUpdateMessage'
\ No newline at end of file
diff --git a/frontend/app/components/ui/SavedSearchList/SavedSearchList.js b/frontend/app/components/ui/SavedSearchList/SavedSearchList.js
index 3bbd8d05b..fc82f1ef0 100644
--- a/frontend/app/components/ui/SavedSearchList/SavedSearchList.js
+++ b/frontend/app/components/ui/SavedSearchList/SavedSearchList.js
@@ -19,7 +19,6 @@ import { funnel as funnelRoute, withSiteId } from 'App/routes';
import Event, { TYPES } from 'Types/filter/event';
import FunnelMenuItem from 'Components/Funnels/FunnelMenuItem';
import FunnelSaveModal from 'Components/Funnels/FunnelSaveModal';
-import NewBadge from 'Shared/NewBadge';
import { blink as setBlink } from 'Duck/funnels';
const DEFAULT_VISIBLE = 3;
@@ -98,7 +97,6 @@ class SavedSearchList extends React.Component {
onClick={ this.createHandler }
/>
)}
- { }
{ funnels.size === 0 &&
diff --git a/frontend/app/player/MessageDistributor/managers/AssistManager.ts b/frontend/app/player/MessageDistributor/managers/AssistManager.ts
index 8f8b16e6c..ea2121464 100644
--- a/frontend/app/player/MessageDistributor/managers/AssistManager.ts
+++ b/frontend/app/player/MessageDistributor/managers/AssistManager.ts
@@ -161,7 +161,6 @@ export default class AssistManager {
if (['peer-unavailable', 'network', 'webrtc'].includes(e.type)) {
if (this.peer && this.connectionAttempts++ < MAX_RECONNECTION_COUNT) {
this.setStatus(ConnectionStatus.Connecting);
- console.log("peerunavailable")
this.connectToPeer();
} else {
this.setStatus(ConnectionStatus.Disconnected);
@@ -175,7 +174,6 @@ export default class AssistManager {
peer.on("open", () => {
if (this.peeropened) { return; }
this.peeropened = true;
- console.log('peeropen')
this.connectToPeer();
});
});
@@ -186,11 +184,9 @@ export default class AssistManager {
if (!this.peer) { return; }
this.setStatus(ConnectionStatus.Connecting);
const id = this.peerID;
- console.log("trying to connect to", id)
const conn = this.peer.connect(id, { serialization: 'json', reliable: true});
conn.on('open', () => {
window.addEventListener("beforeunload", ()=>conn.open &&conn.send("unload"));
- console.log("peer connected")
let i = 0;
let firstMessage = true;
@@ -252,7 +248,6 @@ export default class AssistManager {
const onDataClose = () => {
this.initiateCallEnd();
this.setStatus(ConnectionStatus.Connecting);
- console.log('closed peer conn. Reconnecting...')
this.connectToPeer();
}
@@ -263,7 +258,6 @@ export default class AssistManager {
// }, 3000);
conn.on('close', onDataClose);// Does it work ?
conn.on("error", (e) => {
- console.log("PeerJS connection error", e);
this.setStatus(ConnectionStatus.Error);
})
}
@@ -290,12 +284,10 @@ export default class AssistManager {
private notifyCallEnd() {
const dataConn = this.dataConnection;
if (dataConn) {
- console.log("notifyCallEnd send")
dataConn.send("call_end");
}
}
private initiateCallEnd = () => {
- console.log('initiateCallEnd')
this.forceCallEnd();
this.notifyCallEnd();
this.onCallEnd?.();
@@ -349,7 +341,6 @@ export default class AssistManager {
if (!this.peer || getState().calling !== CallingState.False) { return null; }
update({ calling: CallingState.Requesting });
- console.log('calling...')
const call = this.peer.call(this.peerID, localStream);
call.on('stream', stream => {
@@ -393,12 +384,10 @@ export default class AssistManager {
}
clear() {
- console.log('clearing', this.peerID)
this.initiateCallEnd();
this.dataCheckIntervalID && clearInterval(this.dataCheckIntervalID);
if (this.peer) {
this.peer.connections[this.peerID]?.forEach(c => c.open && c.close());
- console.log("destroying peer...")
this.peer.disconnect();
this.peer.destroy();
this.peer = null;
diff --git a/frontend/app/types/filter/customFilter.js b/frontend/app/types/filter/customFilter.js
index 950c1b61a..ea7d82af2 100644
--- a/frontend/app/types/filter/customFilter.js
+++ b/frontend/app/types/filter/customFilter.js
@@ -1,7 +1,7 @@
import Record from 'Types/Record';
import Target from 'Types/target';
import { camelCased } from 'App/utils';
-// import { getEventIcon } from 'Types/filter';
+import { getEventIcon } from 'Types/filter';
const CLICK = 'CLICK';
const INPUT = 'INPUT';
@@ -105,6 +105,6 @@ export default Record({
operator: event.operator || getOperatorDefault(event.type),
// value: target ? target.label : event.value,
value: typeof value === 'string' ? [value] : value,
- icon: 'filters/metadata'
+ icon: event.type ? getEventIcon(event.type) : 'filters/metadata'
}),
})
diff --git a/frontend/app/types/filter/filter.js b/frontend/app/types/filter/filter.js
index feaa44a20..42637a2fa 100644
--- a/frontend/app/types/filter/filter.js
+++ b/frontend/app/types/filter/filter.js
@@ -124,6 +124,7 @@ export const getEventIcon = (filter) => {
type = type || key;
if (type === KEYS.USER_COUNTRY) return 'map-marker-alt';
if (type === KEYS.USER_BROWSER) return 'window';
+ if (type === KEYS.USERBROWSER) return 'window';
if (type === KEYS.PLATFORM) return 'window';
if (type === TYPES.CLICK) return 'filters/click';
diff --git a/frontend/app/types/session/session.js b/frontend/app/types/session/session.js
index 3926c1901..1fabc79a6 100644
--- a/frontend/app/types/session/session.js
+++ b/frontend/app/types/session/session.js
@@ -75,6 +75,7 @@ export default Record({
crashes: [],
socket: null,
isIOS: false,
+ revId: ''
}, {
fromJS:({
startTs=0,
diff --git a/scripts/helm/README.md b/scripts/helm/README.md
index f4a842546..b3d618665 100644
--- a/scripts/helm/README.md
+++ b/scripts/helm/README.md
@@ -30,11 +30,11 @@ Installation components are separated by namespaces.
**Scripts:**
- **install.sh**
- Installs OpenReplay in a single node machine, for trial runs / demo.
+ Installs OpenReplay in a single node machine.
This script is a wrapper around the `install.sh` with [k3s](https://k3s.io/) as kubernetes distro.
- Note: As of now this script support only ubuntu, as we've to install some packages to enable `NFS`.
+ Note: As of now this script support only Ubuntu, as we've to install some packages to enable `NFS`.
- **kube-install.sh:**
diff --git a/scripts/helm/app/storage.yaml b/scripts/helm/app/storage.yaml
index 836deab4a..39cca7f6b 100644
--- a/scripts/helm/app/storage.yaml
+++ b/scripts/helm/app/storage.yaml
@@ -43,3 +43,4 @@ env:
KAFKA_SERVERS: kafka.db.svc.cluster.local:9092
KAFKA_USE_SSL: false
LICENSE_KEY: ""
+ FS_CLEAN_HRS: 24
diff --git a/scripts/helm/nginx-ingress/nginx-ingress/README.md b/scripts/helm/nginx-ingress/nginx-ingress/README.md
index 76c878b5a..89797d6e4 100644
--- a/scripts/helm/nginx-ingress/nginx-ingress/README.md
+++ b/scripts/helm/nginx-ingress/nginx-ingress/README.md
@@ -4,10 +4,10 @@ This is the frontend of the OpenReplay web app (internet).
## Endpoints
-- /streaming -> ios-proxy
- /api -> chalice
-- /http -> http
- / -> frontend (in minio)
- /assets -> sessions-assets bucket in minio
- /minio -> minio api endpoint
- /ingest -> events ingestor
+- /assist -> live sessions and webRTC
+- /grafana -> monitoring (Enterprise Edition only)
\ No newline at end of file
diff --git a/scripts/helm/nginx-ingress/nginx-ingress/templates/configmap.yaml b/scripts/helm/nginx-ingress/nginx-ingress/templates/configmap.yaml
index fff5ac641..84cc6337d 100644
--- a/scripts/helm/nginx-ingress/nginx-ingress/templates/configmap.yaml
+++ b/scripts/helm/nginx-ingress/nginx-ingress/templates/configmap.yaml
@@ -52,14 +52,6 @@ data:
proxy_set_header Host $host;
proxy_pass $target;
}
- location /streaming/ {
- set $target http://ios-proxy-openreplay.app.svc.cluster.local; rewrite ^/streaming/(.*) /$1 break;
- proxy_http_version 1.1;
- proxy_set_header Upgrade $http_upgrade;
- proxy_set_header Connection "Upgrade";
- proxy_set_header Host $host;
- proxy_pass $target;
- }
location /api/ {
rewrite ^/api/(.*) /$1 break;
proxy_http_version 1.1;