commit
b552e04267
39 changed files with 385 additions and 140 deletions
|
|
@ -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
|
||||
|
||||
|
|
|
|||
71
codeql-analysis.yml
Normal file
71
codeql-analysis.yml
Normal file
|
|
@ -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
|
||||
|
|
@ -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 {
|
|||
/>
|
||||
</div>
|
||||
<div className={cn("side-menu-margined", stl.searchWrapper) }>
|
||||
<TrackerUpdateMessage />
|
||||
<NoSessionsMessage />
|
||||
<div
|
||||
data-hidden={ activeTab === 'live' || activeTab === 'favorite' }
|
||||
|
|
|
|||
|
|
@ -5,24 +5,44 @@ import { NoContent, Loader } from 'UI';
|
|||
import { List, Map } from 'immutable';
|
||||
import SessionItem from 'Shared/SessionItem';
|
||||
|
||||
const AUTOREFRESH_INTERVAL = 1 * 60 * 1000
|
||||
|
||||
interface Props {
|
||||
loading: Boolean,
|
||||
list?: List<any>,
|
||||
fetchList: (params) => void,
|
||||
applyFilter: () => void,
|
||||
filters: List<any>
|
||||
}
|
||||
|
||||
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 (
|
||||
<div>
|
||||
<NoContent
|
||||
title={"No live sessions!"}
|
||||
title={"No live sessions."}
|
||||
subtext={
|
||||
<span>
|
||||
See how to <a target="_blank" className="link" href="https://docs.openreplay.com/plugins/assist">{'enable Assist'}</a> if you haven't yet done so.
|
||||
</span>
|
||||
}
|
||||
image={<img src="/img/live-sessions.png" style={{ width: '70%', marginBottom: '30px' }}/>}
|
||||
show={ !loading && list && list.size === 0}
|
||||
>
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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) {
|
|||
<div className={stl.divider} />
|
||||
<div className="my-3">
|
||||
<SideMenuitem
|
||||
title="Assist"
|
||||
title={ <div className="flex items-center">
|
||||
<div>Assist</div>
|
||||
<div className="ml-2">{ <NewBadge />}</div>
|
||||
</div> }
|
||||
iconName="person"
|
||||
active={activeTab.type === 'live'}
|
||||
onClick={() => onMenuItemClick({ name: 'Assist', type: 'live' })}
|
||||
/>
|
||||
|
||||
</div>
|
||||
|
||||
<div className={stl.divider} />
|
||||
|
|
|
|||
|
|
@ -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 <AssistScript projectKey={projectKey} />
|
||||
case NPM:
|
||||
return <AssistNpm projectKey={projectKey} />
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
return (
|
||||
<div className="p-4">
|
||||
<div>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.</div>
|
||||
|
||||
|
||||
<div className="font-bold my-2">Installation</div>
|
||||
<Highlight className="js">
|
||||
{`npm i @openreplay/tracker-assist`}
|
||||
</Highlight>
|
||||
|
||||
<div className="font-bold my-2">Usage</div>
|
||||
<p>Initialize the tracker then load the @openreplay/tracker-assist plugin.</p>
|
||||
<div className="py-3" />
|
||||
<div className="mb-4" />
|
||||
|
||||
<div className="font-bold my-2">Usage</div>
|
||||
<ToggleContent
|
||||
label="Is SSR?"
|
||||
first={
|
||||
<Highlight className="js">
|
||||
{`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`}
|
||||
</Highlight>
|
||||
}
|
||||
second={
|
||||
<Highlight className="js">
|
||||
{`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();
|
||||
}, [])
|
||||
//...
|
||||
}`}
|
||||
</Highlight>
|
||||
}
|
||||
<Tabs
|
||||
tabs={ TABS }
|
||||
active={ activeTab } onClick={ (tab) => setActiveTab(tab) }
|
||||
/>
|
||||
|
||||
<div className="font-bold my-2">Options</div>
|
||||
<Highlight className="js">
|
||||
{`trackerAssist({
|
||||
confirmText: string;
|
||||
})`}
|
||||
</Highlight>
|
||||
<div className="py-5">
|
||||
{ renderActiveTab() }
|
||||
</div>
|
||||
|
||||
<DocLink className="mt-4" label="Install Assist" url="https://docs.openreplay.com/installation/assist" />
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,53 @@
|
|||
import React from 'react';
|
||||
import Highlight from 'react-highlight'
|
||||
import ToggleContent from 'Shared/ToggleContent'
|
||||
|
||||
function AssistNpm(props) {
|
||||
return (
|
||||
<div>
|
||||
<p>Initialize the tracker then load the @openreplay/tracker-assist plugin.</p>
|
||||
|
||||
<div className="font-bold my-2">Usage</div>
|
||||
<ToggleContent
|
||||
label="Server-Side-Rendered (SSR)?"
|
||||
first={
|
||||
<Highlight className="js">
|
||||
{`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`}
|
||||
</Highlight>
|
||||
}
|
||||
second={
|
||||
<Highlight className="js">
|
||||
{`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();
|
||||
}, [])
|
||||
//...
|
||||
}`}
|
||||
</Highlight>
|
||||
}
|
||||
/>
|
||||
|
||||
<div className="font-bold my-2">Options</div>
|
||||
<Highlight className="js">
|
||||
{`trackerAssist({
|
||||
confirmText: string;
|
||||
})`}
|
||||
</Highlight>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default AssistNpm;
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
import React from 'react';
|
||||
import Highlight from 'react-highlight'
|
||||
|
||||
function AssistScript(props) {
|
||||
return (
|
||||
<div>
|
||||
<p>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:</p>
|
||||
<div className="py-3" />
|
||||
|
||||
<Highlight className="js">
|
||||
{`<!-- OpenReplay Tracking Code -->
|
||||
<script>
|
||||
(function(A,s,a,y,e,r){
|
||||
r=window.OpenReplay=[s,r,e,[y-1]];
|
||||
s=document.createElement('script');s.src=a;s.async=!A;
|
||||
document.getElementsByTagName('head')[0].appendChild(s);
|
||||
r.start=function(v){r.push([0])};
|
||||
r.stop=function(v){r.push([1])};
|
||||
r.setUserID=function(id){r.push([2,id])};
|
||||
r.setUserAnonymousID=function(id){r.push([3,id])};
|
||||
r.setMetadata=function(k,v){r.push([4,k,v])};
|
||||
r.event=function(k,p,i){r.push([5,k,p,i])};
|
||||
r.issue=function(k,p){r.push([6,k,p])};
|
||||
r.isActive=function(){return false};
|
||||
r.getSessionToken=function(){};
|
||||
})(0, "${props.projectKey}", "//static.openreplay.com/3.3.1/openreplay-assist.js",1,28);
|
||||
</script>`}
|
||||
</Highlight>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default AssistScript;
|
||||
|
|
@ -3,6 +3,7 @@ import ToggleContent from 'Shared/ToggleContent'
|
|||
import DocLink from 'Shared/DocLink/DocLink';
|
||||
|
||||
const FetchDoc = (props) => {
|
||||
const { projectKey } = props;
|
||||
return (
|
||||
<div className="p-4">
|
||||
<div>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.</div>
|
||||
|
|
@ -18,14 +19,14 @@ const FetchDoc = (props) => {
|
|||
|
||||
<div className="font-bold my-2">Usage</div>
|
||||
<ToggleContent
|
||||
label="Is SSR?"
|
||||
label="Server-Side-Rendered (SSR)?"
|
||||
first={
|
||||
<Highlight className="js">
|
||||
{`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() {
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ import DocLink from 'Shared/DocLink/DocLink';
|
|||
import ToggleContent from 'Shared/ToggleContent';
|
||||
|
||||
const GraphQLDoc = (props) => {
|
||||
const { projectKey } = props;
|
||||
return (
|
||||
<div className="p-4">
|
||||
<p>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.</p>
|
||||
|
|
@ -19,14 +20,14 @@ const GraphQLDoc = (props) => {
|
|||
<div className="py-3" />
|
||||
|
||||
<ToggleContent
|
||||
label="Is SSR?"
|
||||
label="Server-Side-Rendered (SSR)?"
|
||||
first={
|
||||
<Highlight className="js">
|
||||
{`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() {
|
||||
|
|
|
|||
|
|
@ -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 <SentryForm onClose={ this.closeModal } />;
|
||||
|
|
@ -172,21 +176,21 @@ export default class Integrations extends React.PureComponent {
|
|||
case JIRA:
|
||||
return <JiraForm onClose={ this.closeModal } />;
|
||||
case REDUX:
|
||||
return <ReduxDoc onClose={ this.closeModal } />
|
||||
return <ReduxDoc onClose={ this.closeModal } projectKey={projectKey} />
|
||||
case VUE:
|
||||
return <VueDoc onClose={ this.closeModal } />
|
||||
return <VueDoc onClose={ this.closeModal } projectKey={projectKey} />
|
||||
case GRAPHQL:
|
||||
return <GraphQLDoc onClose={ this.closeModal } />
|
||||
return <GraphQLDoc onClose={ this.closeModal } projectKey={projectKey} />
|
||||
case NGRX:
|
||||
return <NgRxDoc onClose={ this.closeModal } />
|
||||
return <NgRxDoc onClose={ this.closeModal } projectKey={projectKey} />
|
||||
case FETCH:
|
||||
return <FetchDoc onClose={ this.closeModal } />
|
||||
return <FetchDoc onClose={ this.closeModal } projectKey={projectKey} />
|
||||
case MOBX:
|
||||
return <MobxDoc onClose={ this.closeModal } />
|
||||
return <MobxDoc onClose={ this.closeModal } projectKey={projectKey} />
|
||||
case PROFILER:
|
||||
return <ProfilerDoc onClose={ this.closeModal } />
|
||||
return <ProfilerDoc onClose={ this.closeModal } projectKey={projectKey} />
|
||||
case ASSIST:
|
||||
return <AssistDoc onClose={ this.closeModal } />
|
||||
return <AssistDoc onClose={ this.closeModal } projectKey={projectKey} />
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ import ToggleContent from 'Shared/ToggleContent'
|
|||
import DocLink from 'Shared/DocLink/DocLink';
|
||||
|
||||
const MobxDoc = (props) => {
|
||||
const { projectKey } = props;
|
||||
return (
|
||||
<div className="p-4">
|
||||
<div>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.</div>
|
||||
|
|
@ -18,14 +19,14 @@ const MobxDoc = (props) => {
|
|||
|
||||
<div className="font-bold my-2">Usage</div>
|
||||
<ToggleContent
|
||||
label="Is SSR?"
|
||||
label="Server-Side-Rendered (SSR)?"
|
||||
first={
|
||||
<Highlight className="js">
|
||||
{`import OpenReplay from '@openreplay/tracker';
|
||||
import trackerMobX from '@openreplay/tracker-mobx';
|
||||
//...
|
||||
const tracker = new OpenReplay({
|
||||
projectKey: PROJECT_KEY
|
||||
projectKey: '${projectKey}'
|
||||
});
|
||||
tracker.use(trackerMobX(<options>)); // 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(<options>)); // check list of available options below
|
||||
//...
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ import ToggleContent from 'Shared/ToggleContent'
|
|||
import DocLink from 'Shared/DocLink/DocLink';
|
||||
|
||||
const NgRxDoc = (props) => {
|
||||
const { projectKey } = props;
|
||||
return (
|
||||
<div className="p-4">
|
||||
<div>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.</div>
|
||||
|
|
@ -18,7 +19,7 @@ const NgRxDoc = (props) => {
|
|||
|
||||
<div className="font-bold my-2">Usage</div>
|
||||
<ToggleContent
|
||||
label="Is SSR?"
|
||||
label="Server-Side-Rendered (SSR)?"
|
||||
first={
|
||||
<Highlight className="js">
|
||||
{`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() {
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ import ToggleContent from 'Shared/ToggleContent'
|
|||
import DocLink from 'Shared/DocLink/DocLink';
|
||||
|
||||
const ProfilerDoc = (props) => {
|
||||
const { projectKey } = props;
|
||||
return (
|
||||
<div className="p-4">
|
||||
<div>The profiler plugin allows you to measure your JS functions' performance and capture both arguments and result for each function call.</div>
|
||||
|
|
@ -18,14 +19,14 @@ const ProfilerDoc = (props) => {
|
|||
|
||||
<div className="font-bold my-2">Usage</div>
|
||||
<ToggleContent
|
||||
label="Is SSR?"
|
||||
label="Server-Side-Rendered (SSR)?"
|
||||
first={
|
||||
<Highlight className="js">
|
||||
{`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() {
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ import ToggleContent from '../../../shared/ToggleContent';
|
|||
import DocLink from 'Shared/DocLink/DocLink';
|
||||
|
||||
const ReduxDoc = (props) => {
|
||||
const { projectKey } = props;
|
||||
return (
|
||||
<div className="p-4">
|
||||
<div>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.</div>
|
||||
|
|
@ -17,7 +18,7 @@ const ReduxDoc = (props) => {
|
|||
<p>Initialize the tracker then put the generated middleware into your Redux chain.</p>
|
||||
<div className="py-3" />
|
||||
<ToggleContent
|
||||
label="Is SSR?"
|
||||
label="Server-Side-Rendered (SSR)?"
|
||||
first={
|
||||
<Highlight className="js">
|
||||
{`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() {
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ import ToggleContent from '../../../shared/ToggleContent';
|
|||
import DocLink from 'Shared/DocLink/DocLink';
|
||||
|
||||
const VueDoc = (props) => {
|
||||
const { projectKey } = props;
|
||||
return (
|
||||
<div className="p-4">
|
||||
<div>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.</div>
|
||||
|
|
@ -18,7 +19,7 @@ const VueDoc = (props) => {
|
|||
|
||||
|
||||
<ToggleContent
|
||||
label="Is SSR?"
|
||||
label="Server-Side-Rendered (SSR)?"
|
||||
first={
|
||||
<Highlight className="js">
|
||||
{`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() {
|
||||
|
|
|
|||
|
|
@ -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(() => {
|
||||
|
|
|
|||
|
|
@ -72,7 +72,7 @@ function PreferencesMenu({ activeTab, appearance, history }) {
|
|||
<div className="mb-4">
|
||||
<SideMenuitem
|
||||
active={ activeTab === CLIENT_TABS.MANAGE_USERS }
|
||||
title="Manage Users"
|
||||
title="Users"
|
||||
iconName="users"
|
||||
onClick={() => setTab(CLIENT_TABS.MANAGE_USERS) }
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -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 (
|
||||
<form className={ styles.formWrapper } onSubmit={ this.onSubmit }>
|
||||
<div className={ styles.content }>
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@
|
|||
.activeLink {
|
||||
cursor: pointer;
|
||||
pointer-events: default;
|
||||
text-decoration: underline;
|
||||
& label {
|
||||
color: #000000 !important;
|
||||
text-decoration: underline;
|
||||
|
|
|
|||
|
|
@ -22,7 +22,6 @@ class TrackingCodeModal extends React.PureComponent {
|
|||
}
|
||||
|
||||
renderActiveTab = () => {
|
||||
console.log('rendering...')
|
||||
switch (this.state.activeTab) {
|
||||
case PROJECT:
|
||||
return <ProjectCodeSnippet />
|
||||
|
|
|
|||
|
|
@ -4,9 +4,10 @@ import PageInsightsPanel from '../Session_/PageInsightsPanel/PageInsightsPanel'
|
|||
import { Controls as PlayerControls } from 'Player';
|
||||
import { Tabs } from 'UI';
|
||||
import { connectPlayer } from 'Player';
|
||||
import NewBadge from 'Shared/NewBadge';
|
||||
|
||||
const EVENTS = 'Events';
|
||||
const HEATMAPS = 'Heatmaps';
|
||||
const HEATMAPS = 'Click Map';
|
||||
|
||||
const TABS = [ EVENTS, HEATMAPS ].map(tab => ({ text: tab, key: tab }));
|
||||
|
||||
|
|
@ -29,12 +30,15 @@ export default function RightBlock() {
|
|||
}
|
||||
return (
|
||||
<div style={{ width: '270px', height: 'calc(100vh- 50px)'}} className="flex flex-col">
|
||||
<Tabs
|
||||
tabs={ TABS }
|
||||
active={ activeTab }
|
||||
onClick={ (tab) => setActiveTab(tab) }
|
||||
border={ true }
|
||||
/>
|
||||
<div className="relative">
|
||||
<Tabs
|
||||
tabs={ TABS }
|
||||
active={ activeTab }
|
||||
onClick={ (tab) => setActiveTab(tab) }
|
||||
border={ true }
|
||||
/>
|
||||
<div className="absolute" style={{ left: '160px', top: '13px' }}>{ <NewBadge />}</div>
|
||||
</div>
|
||||
{
|
||||
renderActiveTab(activeTab)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -42,7 +42,9 @@ export default class EventsBlock extends React.PureComponent {
|
|||
this.props.setEventFilter({ query: value, filter })
|
||||
|
||||
setTimeout(() => {
|
||||
this.scroller.current.scrollToRow(0);
|
||||
if (!this.scroller.current) return;
|
||||
|
||||
this.scroller.current.scrollToRow(0);
|
||||
}, 100)
|
||||
}
|
||||
|
||||
|
|
@ -54,7 +56,9 @@ export default class EventsBlock extends React.PureComponent {
|
|||
this.scroller.current.forceUpdateGrid();
|
||||
|
||||
setTimeout(() => {
|
||||
this.scroller.current.scrollToRow(0);
|
||||
if (!this.scroller.current) return;
|
||||
|
||||
this.scroller.current.scrollToRow(0);
|
||||
}, 100)
|
||||
}
|
||||
|
||||
|
|
@ -176,6 +180,7 @@ export default class EventsBlock extends React.PureComponent {
|
|||
userNumericHash,
|
||||
userDisplayName,
|
||||
userId,
|
||||
revId,
|
||||
userAnonymousId
|
||||
},
|
||||
filteredEvents
|
||||
|
|
@ -191,6 +196,7 @@ export default class EventsBlock extends React.PureComponent {
|
|||
userNumericHash={userNumericHash}
|
||||
userDisplayName={userDisplayName}
|
||||
userId={userId}
|
||||
revId={revId}
|
||||
userAnonymousId={userAnonymousId}
|
||||
/>
|
||||
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ import Metadata from '../Metadata'
|
|||
import { withRequest } from 'HOCs'
|
||||
import SessionList from '../Metadata/SessionList'
|
||||
|
||||
function UserCard({ className, userNumericHash, userDisplayName, similarSessions, userId, userAnonymousId, request, loading }) {
|
||||
function UserCard({ className, userNumericHash, userDisplayName, similarSessions, userId, userAnonymousId, request, loading, revId }) {
|
||||
const [showUserSessions, setShowUserSessions] = useState(false)
|
||||
const hasUserDetails = !!userId || !!userAnonymousId;
|
||||
|
||||
|
|
@ -29,6 +29,11 @@ function UserCard({ className, userNumericHash, userDisplayName, similarSessions
|
|||
</TextEllipsis>
|
||||
</div>
|
||||
</div>
|
||||
{revId && (
|
||||
<div className="border-t py-2 px-3">
|
||||
<span className="font-medium">Rev ID:</span> {revId}
|
||||
</div>
|
||||
)}
|
||||
<div className="border-t">
|
||||
<Metadata />
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ import BottomBlock from '../BottomBlock';
|
|||
@connect(state => ({
|
||||
session: state.getIn([ 'sessions', 'current' ]),
|
||||
errorStack: state.getIn([ 'sessions', 'errorStack' ]),
|
||||
sourceMapUploaded: state.getIn([ 'sessions', 'sourceMapUploaded' ]),
|
||||
sourcemapUploaded: state.getIn([ 'sessions', 'sourcemapUploaded' ]),
|
||||
loading: state.getIn([ 'sessions', 'fetchErrorStackList', 'loading' ])
|
||||
}), { fetchErrorStackList })
|
||||
export default class Exceptions extends React.PureComponent {
|
||||
|
|
@ -33,7 +33,7 @@ export default class Exceptions extends React.PureComponent {
|
|||
closeModal = () => this.setState({ currentError: null})
|
||||
|
||||
render() {
|
||||
const { exceptions, loading, errorStack, sourceMapUploaded } = this.props;
|
||||
const { exceptions, loading, errorStack, sourcemapUploaded } = this.props;
|
||||
const { filter, currentError } = this.state;
|
||||
const filterRE = getRE(filter, 'i');
|
||||
|
||||
|
|
@ -63,7 +63,7 @@ export default class Exceptions extends React.PureComponent {
|
|||
show={ !loading && errorStack.size === 0 }
|
||||
title="Nothing found!"
|
||||
>
|
||||
<ErrorDetails error={ currentError.name } errorStack={errorStack} sourceMapUploaded={sourceMapUploaded} />
|
||||
<ErrorDetails error={ currentError.name } errorStack={errorStack} sourcemapUploaded={sourcemapUploaded} />
|
||||
</NoContent>
|
||||
</Loader>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -399,7 +399,7 @@ export default class Controls extends React.Component {
|
|||
icon="tachometer-slow"
|
||||
/>
|
||||
}
|
||||
{ !live && showLongtasks &&
|
||||
{/* { !live && showLongtasks &&
|
||||
<ControlButton
|
||||
disabled={ disabled }
|
||||
onClick={ () => toggleBottomBlock(LONGTASKS) }
|
||||
|
|
@ -407,7 +407,7 @@ export default class Controls extends React.Component {
|
|||
label="Long Tasks"
|
||||
icon="business-time"
|
||||
/>
|
||||
}
|
||||
} */}
|
||||
<div className={ styles.divider } />
|
||||
{ !live &&
|
||||
<React.Fragment>
|
||||
|
|
|
|||
|
|
@ -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 })
|
||||
|
|
|
|||
|
|
@ -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 ? (
|
||||
<>
|
||||
{(
|
||||
<div>
|
||||
<div
|
||||
className="rounded text-sm flex items-center justify-between mb-4"
|
||||
style={{ height: '42px', backgroundColor: 'rgba(255, 239, 239, 1)', border: 'solid thin rgba(221, 181, 181, 1)'}}
|
||||
>
|
||||
<div className="flex items-center w-full">
|
||||
<div className="flex-shrink-0 w-8 flex justify-center">
|
||||
<Icon name="info-circle" size="14" color="gray-darkest" />
|
||||
</div>
|
||||
<div className="ml-2color-gray-darkest mr-auto">
|
||||
Please <a href="#" className="link" onClick={() => props.history.push(withSiteId(onboardingRoute('installing'), siteId))}>update</a> your tracker (Asayer) to the latest OpenReplay version ({window.ENV.TRACKER_VERSION}) to benefit from all new features we recently shipped.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
) : ''
|
||||
}
|
||||
|
||||
export default connect(state => ({
|
||||
site: state.getIn([ 'site', 'instance' ]),
|
||||
sites: state.getIn([ 'site', 'list' ])
|
||||
}))(withRouter(TrackerUpdateMessage))
|
||||
|
|
@ -0,0 +1 @@
|
|||
export { default } from './TrackerUpdateMessage'
|
||||
|
|
@ -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 }
|
||||
/>
|
||||
)}
|
||||
<div className="ml-2">{ <NewBadge />}</div>
|
||||
</div>
|
||||
</div>
|
||||
{ funnels.size === 0 &&
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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'
|
||||
}),
|
||||
})
|
||||
|
|
|
|||
|
|
@ -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';
|
||||
|
|
|
|||
|
|
@ -75,6 +75,7 @@ export default Record({
|
|||
crashes: [],
|
||||
socket: null,
|
||||
isIOS: false,
|
||||
revId: ''
|
||||
}, {
|
||||
fromJS:({
|
||||
startTs=0,
|
||||
|
|
|
|||
|
|
@ -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:**
|
||||
|
||||
|
|
|
|||
|
|
@ -43,3 +43,4 @@ env:
|
|||
KAFKA_SERVERS: kafka.db.svc.cluster.local:9092
|
||||
KAFKA_USE_SSL: false
|
||||
LICENSE_KEY: ""
|
||||
FS_CLEAN_HRS: 24
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
@ -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;
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue