diff --git a/README.md b/README.md
index b943773e6..870d47fcc 100644
--- a/README.md
+++ b/README.md
@@ -69,7 +69,7 @@ For those who want to simply use OpenReplay as a service, [sign up](https://app.
Please refer to the [official OpenReplay documentation](https://docs.openreplay.com/). That should help you troubleshoot common issues. For additional help, you can reach out to us on one of these channels:
-- [Slack](https://slack.openreplay.com) (Connect with our engineers and community)
+- [Discord](https://discord.openreplay.com) (Connect with our engineers and community)
- [GitHub](https://github.com/openreplay/openreplay/issues) (Bug and issue reports)
- [Twitter](https://twitter.com/OpenReplayHQ) (Product updates, Great content)
- [Website chat](https://openreplay.com) (Talk to us)
@@ -80,7 +80,7 @@ We're always on the lookout for contributions to OpenReplay, and we're glad you'
See our [Contributing Guide](CONTRIBUTING.md) for more details.
-Also, feel free to join our [Slack](https://slack.openreplay.com) to ask questions, discuss ideas or connect with our contributors.
+Also, feel free to join our [Discord](https://discord.openreplay.com) to ask questions, discuss ideas or connect with our contributors.
## Roadmap
diff --git a/frontend/app/Router.js b/frontend/app/Router.js
index 89fbdd343..f42f3c456 100644
--- a/frontend/app/Router.js
+++ b/frontend/app/Router.js
@@ -1,3 +1,4 @@
+import React, { lazy, Suspense } from 'react';
import { Switch, Route, Redirect } from 'react-router';
import { BrowserRouter, withRouter } from 'react-router-dom';
import { connect } from 'react-redux';
@@ -5,26 +6,29 @@ import { Notification } from 'UI';
import { Loader } from 'UI';
import { fetchUserInfo } from 'Duck/user';
import withSiteIdUpdater from 'HOCs/withSiteIdUpdater';
-import Login from 'Components/Login/Login';
-import ForgotPassword from 'Components/ForgotPassword/ForgotPassword';
-import UpdatePassword from 'Components/UpdatePassword/UpdatePassword';
-import ClientPure from 'Components/Client/Client';
-import OnboardingPure from 'Components/Onboarding/Onboarding';
-import SessionPure from 'Components/Session/Session';
-import LiveSessionPure from 'Components/Session/LiveSession';
-import AssistPure from 'Components/Assist';
-import BugFinderPure from 'Components/BugFinder/BugFinder';
-import DashboardPure from 'Components/Dashboard/Dashboard';
-import ErrorsPure from 'Components/Errors/Errors';
+const Login = lazy(() => import('Components/Login/Login'));
+const ForgotPassword = lazy(() => import('Components/ForgotPassword/ForgotPassword'));
+const UpdatePassword = lazy(() => import('Components/UpdatePassword/UpdatePassword'));
+const SessionPure = lazy(() => import('Components/Session/Session'));
+const LiveSessionPure = lazy(() => import('Components/Session/LiveSession'));
+const OnboardingPure = lazy(() => import('Components/Onboarding/Onboarding'));
+const ClientPure = lazy(() => import('Components/Client/Client'));
+const AssistPure = lazy(() => import('Components/Assist'));
+const BugFinderPure = lazy(() => import('Components/BugFinder/BugFinder'));
+const DashboardPure = lazy(() => import('Components/Dashboard/NewDashboard'));
+const ErrorsPure = lazy(() => import('Components/Errors/Errors'));
+const FunnelDetails = lazy(() => import('Components/Funnels/FunnelDetails'));
+const FunnelIssueDetails = lazy(() => import('Components/Funnels/FunnelIssueDetails'));
+import WidgetViewPure from 'Components/Dashboard/components/WidgetView';
import Header from 'Components/Header/Header';
// import ResultsModal from 'Shared/Results/ResultsModal';
-import FunnelDetails from 'Components/Funnels/FunnelDetails';
-import FunnelIssueDetails from 'Components/Funnels/FunnelIssueDetails';
import { fetchList as fetchIntegrationVariables } from 'Duck/customField';
import { fetchList as fetchSiteList } from 'Duck/site';
import { fetchList as fetchAnnouncements } from 'Duck/announcements';
import { fetchList as fetchAlerts } from 'Duck/alerts';
import { fetchWatchdogStatus } from 'Duck/watchdogs';
+import { dashboardService } from "App/services";
+import { withStore } from 'App/mstore'
import APIClient from './api_client';
import * as routes from './routes';
@@ -32,9 +36,12 @@ import { OB_DEFAULT_TAB } from 'App/routes';
import Signup from './components/Signup/Signup';
import { fetchTenants } from 'Duck/user';
import { setSessionPath } from 'Duck/sessions';
+import { ModalProvider } from './components/Modal';
+import ModalRoot from './components/Modal/ModalRoot';
const BugFinder = withSiteIdUpdater(BugFinderPure);
const Dashboard = withSiteIdUpdater(DashboardPure);
+const WidgetView = withSiteIdUpdater(WidgetViewPure);
const Session = withSiteIdUpdater(SessionPure);
const LiveSession = withSiteIdUpdater(LiveSessionPure);
const Assist = withSiteIdUpdater(AssistPure);
@@ -46,7 +53,15 @@ const FunnelIssue = withSiteIdUpdater(FunnelIssueDetails);
const withSiteId = routes.withSiteId;
const withObTab = routes.withObTab;
+const METRICS_PATH = routes.metrics();
+const METRICS_DETAILS = routes.metricDetails();
+
const DASHBOARD_PATH = routes.dashboard();
+const DASHBOARD_SELECT_PATH = routes.dashboardSelected();
+const DASHBOARD_METRIC_CREATE_PATH = routes.dashboardMetricCreate();
+const DASHBOARD_METRIC_DETAILS_PATH = routes.dashboardMetricDetails();
+
+// const WIDGET_PATAH = routes.dashboardMetric();
const SESSIONS_PATH = routes.sessions();
const ASSIST_PATH = routes.assist();
const ERRORS_PATH = routes.errors();
@@ -62,6 +77,7 @@ const CLIENT_PATH = routes.client();
const ONBOARDING_PATH = routes.onboarding();
const ONBOARDING_REDIRECT_PATH = routes.onboarding(OB_DEFAULT_TAB);
+@withStore
@withRouter
@connect((state) => {
const siteId = state.getIn([ 'user', 'siteId' ]);
@@ -108,6 +124,8 @@ class Router extends React.Component {
fetchInitialData = () => {
Promise.all([
this.props.fetchUserInfo().then(() => {
+ const { mstore } = this.props
+ mstore.initClient();
this.props.fetchIntegrationVariables()
}),
this.props.fetchSiteList().then(() => {
@@ -153,54 +171,78 @@ class Router extends React.Component {
{!hideHeader && }
-
-
-
- {
- const client = new APIClient(jwt);
- switch (location.pathname) {
- case '/integrations/slack':
- client.post('integrations/slack/add', {
- code: location.search.split('=')[ 1 ],
- state: tenantId,
- });
- break;
+ }>
+
+
+
+
+
+ {
+ const client = new APIClient(jwt);
+ switch (location.pathname) {
+ case '/integrations/slack':
+ client.post('integrations/slack/add', {
+ code: location.search.split('=')[ 1 ],
+ state: tenantId,
+ });
+ break;
+ }
+ return ;
}
- return ;
}
- }
- />
- { onboarding &&
-
- }
- { siteIdList.length === 0 &&
-
- }
-
-
-
-
-
-
-
-
-
- } />
- { routes.redirects.map(([ fr, to ]) => (
-
- )) }
-
+ />
+ { onboarding &&
+
+ }
+ { siteIdList.length === 0 &&
+
+ }
+
+
+
+
+
+
+
+
+
+
+
+ {/*
+
+
+
+ */}
+
+
+
+
+
+
+
+
+
+ } />
+ { routes.redirects.map(([ fr, to ]) => (
+
+ )) }
+
+
+
+
+
+ :
+ }>
+
+
+
+ { !existingTenant && }
+
- :
-
-
-
- { !existingTenant && }
-
- ;
+ ;
}
}
diff --git a/frontend/app/api_client.js b/frontend/app/api_client.js
index a42f19468..626f033ea 100644
--- a/frontend/app/api_client.js
+++ b/frontend/app/api_client.js
@@ -1,5 +1,4 @@
import store from 'App/store';
-
import { queried } from './routes';
const siteIdRequiredPaths = [
@@ -24,6 +23,8 @@ const siteIdRequiredPaths = [
'/assist',
'/heatmaps',
'/custom_metrics',
+ '/dashboards',
+ '/metrics'
// '/custom_metrics/sessions',
];
@@ -68,12 +69,16 @@ export default class APIClient {
this.siteId = siteId;
}
- fetch(path, params, options = { clean: true }) {
+ fetch(path, params, options = { clean: true }) {
if (params !== undefined) {
const cleanedParams = options.clean ? clean(params) : params;
this.init.body = JSON.stringify(cleanedParams);
}
+ if (this.init.method === 'GET') {
+ delete this.init.body;
+ }
+
let fetch = window.fetch;
diff --git a/frontend/app/assets/index.html b/frontend/app/assets/index.html
index a9d4b0f62..03300b45c 100644
--- a/frontend/app/assets/index.html
+++ b/frontend/app/assets/index.html
@@ -12,6 +12,7 @@
+