Compare commits

...
Sign in to create a new pull request.

1 commit

Author SHA1 Message Date
nick-delirium
038d8decd5
ui: drop deprecated router api, start moving routing 2025-03-07 14:35:03 +01:00
94 changed files with 893 additions and 1056 deletions

View file

@ -1,5 +1,5 @@
import React, { lazy, Suspense } from 'react';
import { Switch, Route } from 'react-router-dom';
import { Routes, Route } from 'react-router-dom';
import { Loader } from 'UI';
import withSiteIdUpdater from 'HOCs/withSiteIdUpdater';
@ -46,13 +46,13 @@ function IFrameRoutes(props: Props) {
<Layout hideHeader={true}>
<Loader loading={!!loading} className='flex-1'>
<Suspense fallback={<Loader loading={true} className='flex-1' />}>
<Switch key='content'>
<Routes key='content'>
<Route exact strict path={withSiteId(SESSION_PATH, siteIdList)}
component={enhancedComponents.Session} />
<Route exact strict path={withSiteId(LIVE_SESSION_PATH, siteIdList)}
component={enhancedComponents.LiveSession} />
<Route path='*' render={NotFoundPage} />
</Switch>
</Routes>
</Suspense>
</Loader>
</Layout>

View file

@ -1,6 +1,7 @@
import withSiteIdUpdater from 'HOCs/withSiteIdUpdater';
import React, { Suspense, lazy } from 'react';
import { Redirect, Route, Switch } from 'react-router-dom';
import { useNavigate } from 'react-router'
import { Navigate, Route, Routes } from 'react-router-dom';
import { observer } from 'mobx-react-lite';
import { useStore } from './mstore';
import { GLOBAL_HAS_NO_RECORDINGS } from 'App/constants/storageKeys';
@ -101,6 +102,7 @@ const HIGHLIGHTS_PATH = routes.highlights();
let debounceSearch: any = () => {};
function PrivateRoutes() {
const navigate = useNavigate();
const { projectsStore, userStore, integrationsStore, searchStore } = useStore();
const onboarding = userStore.onboarding;
const scope = userStore.scopeState;
@ -129,34 +131,52 @@ function PrivateRoutes() {
debounceSearch();
}, [searchStore.instance.filters, searchStore.instance.eventsOrder]);
React.useEffect(() => {
if (redirectToSetup) {
navigate(SCOPE_SETUP)
}
}, [redirectToSetup])
React.useEffect(() => {
if (redirectToOnboarding) {
navigate(withSiteId(ONBOARDING_REDIRECT_PATH, siteId))
}
}, [redirectToOnboarding]);
console.log(withSiteId(SESSIONS_PATH, siteIdList))
return (
<Suspense fallback={<Loader loading={true} className="flex-1" />}>
<Switch key="content">
<Routes key="content">
<Route
exact
strict
path={SCOPE_SETUP}
component={enhancedComponents.ScopeSetup}
element={enhancedComponents.ScopeSetup}
/>
{redirectToSetup ? <Redirect to={SCOPE_SETUP} /> : null}
<Route path={CLIENT_PATH} component={enhancedComponents.Client} />
<Route path={CLIENT_PATH} element={enhancedComponents.Client} />
<Route
path={withSiteId(ONBOARDING_PATH, siteIdList)}
component={enhancedComponents.Onboarding}
element={enhancedComponents.Onboarding}
/>
<Route
exact
strict
path={SPOTS_LIST_PATH}
component={enhancedComponents.SpotsList}
element={enhancedComponents.SpotsList}
/>
<Route
exact
strict
path={SPOT_PATH}
component={enhancedComponents.Spot}
element={enhancedComponents.Spot}
/>
{scope === 1 ? <Redirect to={SPOTS_LIST_PATH} /> : null}
{scope === 1
? <Route
path="*"
>
<Redirect to={SPOTS_LIST_PATH} />
</Route>
: null
}
<Route
path="/integrations/"
render={({ location }) => {
@ -175,111 +195,106 @@ function PrivateRoutes() {
});
break;
}
return <Redirect to={CLIENT_PATH} />;
return <Route
path="*"
element={<Navigate to={CLIENT_PATH} />}
/>
}}
/>
{redirectToOnboarding && (
<Redirect to={withSiteId(ONBOARDING_REDIRECT_PATH, siteId)} />
)}
{/* DASHBOARD and Metrics */}
<Route
exact
strict
path={[
withSiteId(ALERTS_PATH, siteIdList),
withSiteId(ALERT_EDIT_PATH, siteIdList),
withSiteId(ALERT_CREATE_PATH, siteIdList),
withSiteId(METRICS_PATH, siteIdList),
withSiteId(METRICS_DETAILS, siteIdList),
withSiteId(METRICS_DETAILS_SUB, siteIdList),
withSiteId(DASHBOARD_PATH, siteIdList),
withSiteId(DASHBOARD_SELECT_PATH, siteIdList),
withSiteId(DASHBOARD_METRIC_CREATE_PATH, siteIdList),
withSiteId(DASHBOARD_METRIC_DETAILS_PATH, siteIdList)
]}
component={enhancedComponents.Dashboard}
/>
{[
withSiteId(ALERTS_PATH, siteIdList),
withSiteId(ALERT_EDIT_PATH, siteIdList),
withSiteId(ALERT_CREATE_PATH, siteIdList),
withSiteId(METRICS_PATH, siteIdList),
withSiteId(METRICS_DETAILS, siteIdList),
withSiteId(METRICS_DETAILS_SUB, siteIdList),
withSiteId(DASHBOARD_PATH, siteIdList),
withSiteId(DASHBOARD_SELECT_PATH, siteIdList),
withSiteId(DASHBOARD_METRIC_CREATE_PATH, siteIdList),
withSiteId(DASHBOARD_METRIC_DETAILS_PATH, siteIdList)
].map((path) => (
<Route
path={path}
element={enhancedComponents.Dashboard}
/>
))}
<Route
exact
strict
path={withSiteId(USABILITY_TESTING_PATH, siteIdList)}
component={enhancedComponents.UsabilityTesting}
element={enhancedComponents.UsabilityTesting}
/>
<Route
exact
strict
path={withSiteId(USABILITY_TESTING_EDIT_PATH, siteIdList)}
component={enhancedComponents.UsabilityTestEdit}
element={enhancedComponents.UsabilityTestEdit}
/>
<Route
exact
strict
path={withSiteId(USABILITY_TESTING_VIEW_PATH, siteIdList)}
component={enhancedComponents.UsabilityTestOverview}
element={enhancedComponents.UsabilityTestOverview}
/>
<Route
exact
path={withSiteId(MULTIVIEW_INDEX_PATH, siteIdList)}
component={enhancedComponents.Multiview}
element={enhancedComponents.Multiview}
/>
<Route
path={withSiteId(MULTIVIEW_PATH, siteIdList)}
component={enhancedComponents.Multiview}
element={enhancedComponents.Multiview}
/>
<Route
exact
strict
path={withSiteId(ASSIST_PATH, siteIdList)}
component={enhancedComponents.Assist}
element={enhancedComponents.Assist}
/>
<Route
exact
strict
path={withSiteId(RECORDINGS_PATH, siteIdList)}
component={enhancedComponents.Assist}
element={enhancedComponents.Assist}
/>
<Route
exact
strict
path={withSiteId(HIGHLIGHTS_PATH, siteIdList)}
component={enhancedComponents.Highlights}
/>
<Route
exact
strict
path={[
withSiteId(SESSIONS_PATH, siteIdList),
withSiteId(FFLAGS_PATH, siteIdList),
withSiteId(FFLAG_PATH, siteIdList),
withSiteId(FFLAG_READ_PATH, siteIdList),
withSiteId(FFLAG_CREATE_PATH, siteIdList),
withSiteId(NOTES_PATH, siteIdList),
withSiteId(BOOKMARKS_PATH, siteIdList)
]}
component={enhancedComponents.SessionsOverview}
element={enhancedComponents.Highlights}
/>
{[
withSiteId(SESSIONS_PATH),
withSiteId(FFLAGS_PATH, siteIdList),
withSiteId(FFLAG_PATH, siteIdList),
withSiteId(FFLAG_READ_PATH, siteIdList),
withSiteId(FFLAG_CREATE_PATH, siteIdList),
withSiteId(NOTES_PATH, siteIdList),
withSiteId(BOOKMARKS_PATH, siteIdList)
].map((path) => (
<Route
path={path}
element={<enhancedComponents.SessionsOverview />}
/>
))}
<Route
exact
strict
path={withSiteId(SESSION_PATH, siteIdList)}
component={enhancedComponents.Session}
element={enhancedComponents.Session}
/>
<Route
exact
strict
path={withSiteId(LIVE_SESSION_PATH, siteIdList)}
component={enhancedComponents.LiveSession}
element={enhancedComponents.LiveSession}
/>
{Object.entries(routes.redirects).map(([fr, to]) => (
<Redirect key={fr} exact strict from={fr} to={to} />
))}
<Route path={'*'}>
<Redirect to={withSiteId(routes.sessions(), siteId)} />
</Route>
</Switch>
{/*<Route path={'*'} element={<Navigate to={withSiteId(routes.sessions(), siteId)} />} />*/}
</Routes>
</Suspense>
);
}

View file

@ -1,6 +1,6 @@
import React, { lazy, Suspense, useEffect } from 'react';
import { Loader } from 'UI';
import { Redirect, Route, Switch } from 'react-router-dom';
import { Navigate, Route, Routes } from 'react-router-dom';
import Signup from 'Components/Signup/Signup';
import SupportCallout from 'Shared/SupportCallout';
import { useStore } from 'App/mstore';
@ -35,13 +35,16 @@ function PublicRoutes() {
return (
<Loader loading={loading} className="flex-1">
<Suspense fallback={<Loader loading={true} className="flex-1" />}>
<Switch>
<Route exact strict path={SPOT_PATH} component={Spot} />
<Route exact strict path={FORGOT_PASSWORD} component={ForgotPassword} />
<Route exact strict path={LOGIN_PATH} component={Login} />
<Route exact strict path={SIGNUP_PATH} component={Signup} />
<Redirect to={LOGIN_PATH} />
</Switch>
<Routes>
<Route exact strict path={SPOT_PATH} element={<Spot />} />
<Route exact strict path={FORGOT_PASSWORD} element={<ForgotPassword />} />
<Route exact strict path={LOGIN_PATH} element={<Login />} />
<Route exact strict path={SIGNUP_PATH} element={Signup} />
<Route
path="*"
element={<Navigate to={LOGIN_PATH} replace />}
/>
</Routes>
{!hideSupport && <SupportCallout />}
</Suspense>
</Loader>

View file

@ -1,6 +1,5 @@
import React, { useEffect, useRef } from 'react';
import { RouteComponentProps, withRouter } from 'react-router-dom';
import { useLocation, useNavigate } from 'react-router'
import IFrameRoutes from 'App/IFrameRoutes';
import PrivateRoutes from 'App/PrivateRoutes';
import PublicRoutes from 'App/PublicRoutes';
@ -19,19 +18,9 @@ import { Loader } from 'UI';
import * as routes from './routes';
import { observer } from 'mobx-react-lite'
interface RouterProps extends RouteComponentProps {
match: {
params: {
siteId: string;
};
};
}
const Router: React.FC<RouterProps> = (props) => {
const {
location,
history,
} = props;
const Router = () => {
const location = useLocation()
const navigate = useNavigate()
const mstore = useStore();
const { customFieldStore, projectsStore, sessionStore, searchStore, userStore } = mstore;
const jwt = userStore.jwt;
@ -113,7 +102,7 @@ const Router: React.FC<RouterProps> = (props) => {
) {
const url = new URL(destinationPath, window.location.origin);
checkParams(url.search);
history.push(destinationPath);
navigate(destinationPath);
localStorage.removeItem(GLOBAL_DESTINATION_PATH);
}
};
@ -219,4 +208,4 @@ const Router: React.FC<RouterProps> = (props) => {
);
};
export default withRouter(observer(Router));
export default observer(Router);

View file

@ -1,13 +1,11 @@
import React from 'react';
import { withRouter } from 'react-router-dom';
import { Switch, Route, Redirect } from 'react-router';
import { Routes, Route, Navigate } from 'react-router';
import { CLIENT_TABS, client as clientRoute } from 'App/routes';
import ProfileSettings from './ProfileSettings';
import Integrations from './Integrations';
import UserView from './Users/UsersView';
import AuditView from './Audit/AuditView';
import Sites from './Sites';
import Projects from './Projects';
import CustomFields from './CustomFields';
import Webhooks from './Webhooks';
@ -16,43 +14,27 @@ import Roles from './Roles';
import SessionsListingSettings from 'Components/Client/SessionsListingSettings';
import Modules from 'Components/Client/Modules';
@withRouter
export default class Client extends React.PureComponent {
constructor(props) {
super(props);
}
setTab = (tab) => {
this.props.history.push(clientRoute(tab));
};
renderActiveTab = () => (
<Switch>
<Route exact strict path={clientRoute(CLIENT_TABS.PROFILE)} component={ProfileSettings} />
<Route exact strict path={clientRoute(CLIENT_TABS.SESSIONS_LISTING)} component={SessionsListingSettings} />
<Route exact strict path={clientRoute(CLIENT_TABS.INTEGRATIONS)} component={Integrations} />
<Route exact strict path={clientRoute(CLIENT_TABS.MANAGE_USERS)} component={UserView} />
<Route exact strict path={clientRoute(CLIENT_TABS.SITES)} component={Projects} />
<Route exact strict path={clientRoute(CLIENT_TABS.CUSTOM_FIELDS)} component={CustomFields} />
<Route exact strict path={clientRoute(CLIENT_TABS.WEBHOOKS)} component={Webhooks} />
<Route exact strict path={clientRoute(CLIENT_TABS.NOTIFICATIONS)} component={Notifications} />
<Route exact strict path={clientRoute(CLIENT_TABS.MANAGE_ROLES)} component={Roles} />
<Route exact strict path={clientRoute(CLIENT_TABS.AUDIT)} component={AuditView} />
<Route exact strict path={clientRoute(CLIENT_TABS.MODULES)} component={Modules} />
<Redirect to={clientRoute(CLIENT_TABS.PROFILE)} />
</Switch>
);
render() {
const {
match: {
params: { activeTab }
}
} = this.props;
return (
<div className='w-full mx-auto mb-8' style={{ maxWidth: '1360px' }}>
{activeTab && this.renderActiveTab()}
</div>
);
}
function Client() {
return (
<div className='w-full mx-auto mb-8' style={{ maxWidth: '1360px' }}>
<Routes>
<Route exact strict path={clientRoute(CLIENT_TABS.PROFILE)} component={ProfileSettings} />
<Route exact strict path={clientRoute(CLIENT_TABS.SESSIONS_LISTING)} component={SessionsListingSettings} />
<Route exact strict path={clientRoute(CLIENT_TABS.INTEGRATIONS)} component={Integrations} />
<Route exact strict path={clientRoute(CLIENT_TABS.MANAGE_USERS)} component={UserView} />
<Route exact strict path={clientRoute(CLIENT_TABS.SITES)} component={Projects} />
<Route exact strict path={clientRoute(CLIENT_TABS.CUSTOM_FIELDS)} component={CustomFields} />
<Route exact strict path={clientRoute(CLIENT_TABS.WEBHOOKS)} component={Webhooks} />
<Route exact strict path={clientRoute(CLIENT_TABS.NOTIFICATIONS)} component={Notifications} />
<Route exact strict path={clientRoute(CLIENT_TABS.MANAGE_ROLES)} component={Roles} />
<Route exact strict path={clientRoute(CLIENT_TABS.AUDIT)} component={AuditView} />
<Route exact strict path={clientRoute(CLIENT_TABS.MODULES)} component={Modules} />
<Route path={'*'}>
<Navigate to={clientRoute(CLIENT_TABS.PROFILE)} />
</Route>
</Routes>
</div>
)
}
export default Client;

View file

@ -1,8 +1,8 @@
import React from 'react';
import { App, Button, Card, Layout, Space, Tooltip, Typography } from 'antd';
import { App, Button, Card, Layout, Tooltip, Typography } from 'antd';
import ProjectList from 'Components/Client/Projects/ProjectList';
import ProjectTabs from 'Components/Client/Projects/ProjectTabs';
import { useHistory } from 'react-router-dom';
import { useNavigate } from 'react-router';
import { useStore } from '@/mstore';
import { observer } from 'mobx-react-lite';
import {PlusOutlined, KeyOutlined} from '@ant-design/icons'
@ -13,12 +13,12 @@ import Project from '@/mstore/types/project';
function Projects() {
const { projectsStore, customFieldStore } = useStore();
const history = useHistory();
const navigate = useNavigate();
const { project, pid, tab } = projectsStore.config;
const { openModal, closeModal } = useModal();
React.useEffect(() => {
const params = new URLSearchParams(history.location.search);
const params = new URLSearchParams(location.search);
const pid = params.get('pid');
const tab = params.get('tab');
projectsStore.setConfigProject(pid ? parseInt(pid) : undefined);
@ -30,7 +30,7 @@ function Projects() {
}, []);
React.useEffect(() => {
const params = new URLSearchParams(history.location.search);
const params = new URLSearchParams(location.search);
if (projectsStore.config.pid) {
params.set('pid', projectsStore.config.pid + '');
}
@ -38,7 +38,8 @@ function Projects() {
if (projectsStore.config.tab) {
params.set('tab', projectsStore.config.tab);
}
history.push({ search: params.toString() });
const search = params.toString();
navigate(location.pathname + '?' + search);
}, [pid, tab]);
const createProject = () => {

View file

@ -1,6 +1,6 @@
import { Segmented } from 'antd';
import React, { ChangeEvent, FormEvent, useEffect, useState } from 'react';
import { RouteComponentProps, withRouter } from 'react-router-dom';
import { useLocation } from 'react-router'
import { toast } from 'react-toastify';
import { useStore } from 'App/mstore';
import { confirm, Form, Icon, Input } from 'UI';
@ -13,9 +13,10 @@ type OwnProps = {
onClose: (arg: any) => void;
};
type Props = RouteComponentProps & OwnProps;
type Props = OwnProps;
const NewSiteForm = ({ location: { pathname }, onClose }: Props) => {
const NewSiteForm = ({ onClose }: Props) => {
const { pathname } = useLocation();
const mstore = useStore();
const { projectsStore } = mstore;
const activeSiteId = projectsStore.active?.id;
@ -170,4 +171,4 @@ const NewSiteForm = ({ location: { pathname }, onClose }: Props) => {
);
};
export default withRouter(observer(NewSiteForm));
export default observer(NewSiteForm);

View file

@ -1,20 +1,15 @@
import React, { useEffect } from 'react';
import { observer } from 'mobx-react-lite';
import { useStore } from 'App/mstore';
import { withRouter, RouteComponentProps } from 'react-router-dom';
import { useNavigate, useParams } from "react-router";
import { Loader } from 'UI';
import { withSiteId, dashboard, metrics } from "App/routes";
import DashboardRouter from './components/DashboardRouter';
import withPermissions from 'HOCs/withPermissions';
interface RouterProps {
siteId: string;
dashboardId: string;
metricId: string;
}
function NewDashboard(props: RouteComponentProps<RouterProps>) {
const { history, match: { params: { siteId, dashboardId } } } = props;
function NewDashboard() {
const { siteId, dashboardId } = useParams()
const navigate = useNavigate();
const { dashboardStore } = useStore();
const initId = React.useRef(siteId)
const loading = dashboardStore.isLoading;
@ -23,10 +18,10 @@ function NewDashboard(props: RouteComponentProps<RouterProps>) {
useEffect(() => {
if (siteId !== initId.current) {
if (isMetricListMetric) {
history.push(withSiteId(metrics(), siteId))
navigate(withSiteId(metrics(), siteId))
}
if (isDbMetric) {
history.push(withSiteId(dashboard(), siteId))
navigate(withSiteId(dashboard(), siteId))
}
}
dashboardStore.fetchList().then((resp) => {
@ -43,4 +38,4 @@ function NewDashboard(props: RouteComponentProps<RouterProps>) {
);
}
export default withRouter(withPermissions(['METRICS'])(observer(NewDashboard)));
export default withPermissions(['METRICS'])(observer(NewDashboard))

View file

@ -1,7 +1,7 @@
import React, { useEffect } from "react";
import { Pagination, NoContent, Icon } from "UI";
import ErrorListItem from "App/components/Dashboard/components/Errors/ErrorListItem";
import { withRouter, RouteComponentProps } from "react-router-dom";
import { useLocation, useNavigate } from "react-router";
import { useModal } from "App/components/Modal";
import ErrorDetailsModal from "App/components/Dashboard/components/Errors/ErrorDetailsModal";
@ -9,19 +9,18 @@ interface Props {
metric: any;
data: any;
isEdit: any;
history: any;
location: any;
}
function CustomMetricTableErrors(props: RouteComponentProps & Props) {
function CustomMetricTableErrors(props: Props) {
const { metric, data } = props;
const errorId = new URLSearchParams(props.location.search).get("errorId");
const location = useLocation();
const navigate = useNavigate();
const errorId = new URLSearchParams(location.search).get("errorId");
const { showModal, hideModal } = useModal();
const onErrorClick = (e: any, error: any) => {
e.stopPropagation();
props.history.replace({
search: new URLSearchParams({ errorId: error.errorId }).toString(),
});
const search = new URLSearchParams({ errorId: error.errorId }).toString()
navigate(location.pathname + "?" + search, { replace: true });
};
useEffect(() => {
@ -31,8 +30,8 @@ function CustomMetricTableErrors(props: RouteComponentProps & Props) {
right: true,
width: 1200,
onClose: () => {
if (props.history.location.pathname.includes("/dashboard") || props.history.location.pathname.includes("/metrics/")) {
props.history.replace({ search: "" });
if (location.pathname.includes("/dashboard") || location.pathname.includes("/metrics/")) {
navigate(location.pathname, { replace: true });
}
},
});
@ -60,7 +59,6 @@ function CustomMetricTableErrors(props: RouteComponentProps & Props) {
</div>
))}
{/*{isEdit && (*/}
<div className="my-6 flex items-center justify-center">
<Pagination
page={metric.page}
@ -72,25 +70,9 @@ function CustomMetricTableErrors(props: RouteComponentProps & Props) {
debounceRequest={500}
/>
</div>
{/*)}*/}
{/*{!isEdit && (*/}
{/* <ViewMore total={data.total} limit={5} />*/}
{/*)}*/}
</div>
</NoContent>
);
}
export default withRouter<Props & RouteComponentProps, React.FunctionComponent>(CustomMetricTableErrors);
const ViewMore = ({ total, limit }: any) =>
total > limit && (
<div className="mt-4 flex items-center justify-center cursor-pointer w-fit mx-auto">
<div className="text-center">
<div className="color-teal text-lg">
All <span className="font-medium">{total}</span> errors
</div>
</div>
</div>
);
export default CustomMetricTableErrors;

View file

@ -25,7 +25,7 @@ import {
USER_PATH,
CATEGORIES,
} from 'App/constants/card';
import { useHistory } from 'react-router-dom';
import { useNavigate } from 'react-router';
import { dashboardMetricCreate, withSiteId, metricCreate } from 'App/routes';
import { FilterKey } from 'Types/filter/filterType';
import MetricsLibraryModal from '../MetricsLibraryModal/MetricsLibraryModal';
@ -183,16 +183,16 @@ function CategoryTab({
}) {
const items = isMobile ? mobileTabItems[tab] : tabItems[tab];
const { projectsStore, dashboardStore } = useStore();
const history = useHistory();
const navigate = useNavigate();
const handleCardSelection = (card: string) => {
if (projectsStore.activeSiteId) {
if (inCards) {
history.push(
navigate(
withSiteId(metricCreate(), projectsStore.activeSiteId) + `?mk=${card}`
);
} else if (dashboardStore.selectedDashboard) {
history.push(
navigate(
withSiteId(
dashboardMetricCreate(dashboardStore.selectedDashboard.dashboardId),
projectsStore.activeSiteId

View file

@ -6,10 +6,10 @@ import { withSiteId, alertEdit } from 'App/routes';
import { numberWithCommas } from 'App/utils';
// @ts-ignore
import { DateTime } from 'luxon';
import { withRouter, RouteComponentProps } from 'react-router-dom';
import cn from 'classnames';
import Alert from 'Types/alert';
import { observer } from 'mobx-react-lite'
import { useNavigate } from 'react-router';
const getThreshold = (threshold: number) => {
if (threshold === 15) return '15 Minutes';
@ -84,7 +84,8 @@ interface Props extends RouteComponentProps {
}
function AlertListItem(props: Props) {
const { alert, siteId, history, init, demo, webhooks, triggerOptions } = props;
const { alert, siteId, init, demo, webhooks, triggerOptions } = props;
const navigate = useNavigate();
if (!alert) {
return null;
@ -94,7 +95,7 @@ function AlertListItem(props: Props) {
if (demo) return;
const path = withSiteId(alertEdit(alert.alertId), siteId);
init(alert || {});
history.push(path);
navigate(path);
};
const formTriggerName = () =>
@ -169,4 +170,4 @@ function AlertListItem(props: Props) {
);
}
export default withRouter(observer(AlertListItem));
export default observer(AlertListItem);

View file

@ -1,5 +1,5 @@
import React, { useEffect } from 'react';
import { PageTitle, Icon, Link } from 'UI';
import { PageTitle, Link } from 'UI';
import { Button } from 'antd';
import { PlusOutlined } from '@ant-design/icons';
import withPageTitle from 'HOCs/withPageTitle';
@ -7,7 +7,7 @@ import { withSiteId, alertCreate } from 'App/routes';
import AlertsList from './AlertsList';
import AlertsSearch from './AlertsSearch';
import { useHistory } from 'react-router';
import { useLocation } from 'react-router';
import { useStore } from 'App/mstore';
interface IAlertsView {
@ -15,18 +15,16 @@ interface IAlertsView {
}
function AlertsView({ siteId }: IAlertsView) {
const history = useHistory();
const location = useLocation();
const { alertsStore } = useStore();
useEffect(() => {
const unmount = history.listen((location) => {
return () => {
if (!location.pathname.includes('/alert')) {
alertsStore.updateKey('page', 1);
}
});
return unmount;
}, [history]);
}
}, [location.pathname]);
return (
<div style={{ maxWidth: '1360px', margin: 'auto'}} className="bg-white rounded-lg shadow-sm py-4 border">
<div className="flex items-center mb-4 justify-between px-6">

View file

@ -6,7 +6,6 @@ import { toast } from 'react-toastify';
import { SLACK, WEBHOOK, TEAMS } from 'App/constants/schedule';
import Breadcrumb from 'Shared/Breadcrumb';
import { withSiteId, alerts } from 'App/routes';
import { withRouter, RouteComponentProps } from 'react-router-dom';
import { useStore } from 'App/mstore'
import { observer } from 'mobx-react-lite'
import Alert from 'Types/alert'
@ -16,6 +15,7 @@ import BottomButtons from './AlertForm/BottomButtons';
import NotifyHooks from './AlertForm/NotifyHooks';
import AlertListItem from './AlertListItem';
import Condition from './AlertForm/Condition';
import { useNavigate } from "react-router";
const Circle = ({ text }: { text: string }) => (
<div
@ -52,7 +52,7 @@ interface Select {
value: string | number
}
interface IProps extends RouteComponentProps {
interface IProps {
siteId: string;
slackChannels: any[];
loading: boolean;
@ -63,7 +63,9 @@ interface IProps extends RouteComponentProps {
}
const NewAlert = (props: IProps) => {
const { alertsStore, settingsStore } = useStore();
const navigate = useNavigate();
const { alertsStore, settingsStore, projectsStore } = useStore();
const siteId = projectsStore.activeSiteId
const {
fetchTriggerOptions,
init,
@ -80,9 +82,6 @@ const NewAlert = (props: IProps) => {
const deleting = loading
const webhooks = settingsStore.webhooks
const fetchWebhooks = settingsStore.fetchWebhooks
const {
siteId,
} = props;
useEffect(() => {
init({});
@ -120,7 +119,7 @@ const NewAlert = (props: IProps) => {
})
) {
remove(instance.alertId).then(() => {
props.history.push(withSiteId(alerts(), siteId));
navigate(withSiteId(alerts(), siteId));
toast.success('Alert deleted');
}).catch(() => {
toast.error('Failed to delete an alert');
@ -133,7 +132,7 @@ const NewAlert = (props: IProps) => {
save(instance).then(() => {
if (!wasUpdating) {
toast.success('New alert saved');
props.history.push(withSiteId(alerts(), siteId));
navigate(withSiteId(alerts(), siteId));
} else {
toast.success('Alert updated');
}
@ -296,4 +295,4 @@ const NewAlert = (props: IProps) => {
);
};
export default withRouter(observer(NewAlert))
export default observer(NewAlert)

View file

@ -1,21 +1,19 @@
import { useModal } from 'App/components/Modal';
import { observer } from 'mobx-react-lite';
import React, { useEffect, useState } from 'react';
import { RouteComponentProps, withRouter } from 'react-router';
import { Loader, Pagination } from 'UI';
import { Button } from 'antd'
import SessionsModal from './SessionsModal';
import CardUserItem from './CardUserItem';
import { useStore } from 'App/mstore';
import { useNavigate, useLocation } from 'react-router';
interface Props {
history: any;
location: any;
}
function CardUserList(props: RouteComponentProps<Props>) {
function CardUserList() {
const navigate = useNavigate();
const location = useLocation();
const [loading, setLoading] = useState(false);
const { showModal } = useModal();
const userId = new URLSearchParams(props.location.search).get("userId");
const userId = new URLSearchParams(location.search).get("userId");
const { metricStore, dashboardStore } = useStore();
const [data, setData] = useState<any>([
@ -27,7 +25,8 @@ function CardUserList(props: RouteComponentProps<Props>) {
const pageSize = data.length;
const handleClick = (issue: any) => {
props.history.replace({search: (new URLSearchParams({userId : '123'})).toString()});
const search = (new URLSearchParams({userId : '123'})).toString()
navigate(location.pathname + "?" + search, { replace: true });
// showModal(<SessionsModal list={[]} />, { right: true, width: 450 })
}
@ -35,8 +34,8 @@ function CardUserList(props: RouteComponentProps<Props>) {
if (!userId) return;
showModal(<SessionsModal userId={userId} name="test" hash="test" />, { right: true, width: 600, onClose: () => {
if (props.history.location.pathname.includes("/metric")) {
props.history.replace({search: ""});
if (location.pathname.includes("/metric")) {
navigate(location.pathname, { replace: true });
}
}});
}, [userId]);
@ -75,4 +74,4 @@ function CardUserList(props: RouteComponentProps<Props>) {
);
}
export default withRouter(observer(CardUserList));
export default observer(CardUserList);

View file

@ -2,7 +2,7 @@ import React from 'react';
import { PlusOutlined } from '@ant-design/icons';
import { Button } from 'antd';
import { useStore } from 'App/mstore';
import { useHistory } from 'react-router-dom';
import { useNavigate } from 'react-router';
interface Props {
disabled?: boolean;
@ -12,7 +12,7 @@ function CreateDashboardButton({ disabled }: Props) {
const [dashboardCreating, setDashboardCreating] = React.useState(false);
const { projectsStore, dashboardStore } = useStore();
const siteId = projectsStore.siteId;
const history = useHistory();
const navigate = useNavigate();
const createNewDashboard = async () => {
setDashboardCreating(true);
@ -21,7 +21,7 @@ function CreateDashboardButton({ disabled }: Props) {
.save(dashboardStore.dashboardInstance)
.then(async (syncedDashboard) => {
dashboardStore.selectDashboardById(syncedDashboard.dashboardId);
history.push(`/${siteId}/dashboard/${syncedDashboard.dashboardId}`);
navigate(`/${siteId}/dashboard/${syncedDashboard.dashboardId}`);
})
.finally(() => {
setDashboardCreating(false);

View file

@ -2,23 +2,21 @@ import React from 'react';
import { useStore } from 'App/mstore';
import { SideMenuitem, Icon } from 'UI';
import { withSiteId, dashboardSelected } from 'App/routes';
import { withRouter } from 'react-router-dom';
import { useNavigate } from 'react-router';
import { useModal } from 'App/components/Modal';
interface Props {
siteId: string
history: any
}
function DashbaordListModal(props: Props) {
const { dashboardStore } = useStore();
function DashbaordListModal() {
const navigate = useNavigate();
const { dashboardStore, projectsStore } = useStore();
const siteId = projectsStore.activeSiteId;
const { hideModal } = useModal();
const dashboards = dashboardStore.dashboards;
const activeDashboardId = dashboardStore.selectedDashboard?.dashboardId;
const onItemClick = (dashboard) => {
dashboardStore.selectDashboardById(dashboard.dashboardId);
const path = withSiteId(dashboardSelected(dashboard.dashboardId), parseInt(props.siteId));
props.history.push(path);
const path = withSiteId(dashboardSelected(dashboard.dashboardId), parseInt(siteId));
navigate(path);
hideModal();
};
return (
@ -46,4 +44,4 @@ function DashbaordListModal(props: Props) {
);
}
export default withRouter(DashbaordListModal);
export default DashbaordListModal;

View file

@ -1,7 +1,6 @@
import React from 'react';
import BackButton from 'Shared/Breadcrumb/BackButton';
import { withSiteId } from 'App/routes';
import { withRouter, RouteComponentProps } from 'react-router-dom';
import { PageTitle, confirm } from 'UI';
import { Tooltip, Popover, Button } from 'antd';
import { PlusOutlined } from '@ant-design/icons';
@ -12,21 +11,23 @@ import withModal from 'App/components/Modal/withModal';
import { observer } from 'mobx-react-lite';
import DashboardEditModal from '../DashboardEditModal';
import AddCardSection from '../AddCardSection/AddCardSection';
import { useNavigate } from "react-router";
interface IProps {
siteId: string;
renderReport?: any;
}
type Props = IProps & RouteComponentProps;
type Props = IProps;
function DashboardHeader(props: Props) {
const { siteId } = props;
const navigate = useNavigate();
const [popoverOpen, setPopoverOpen] = React.useState(false);
const handleOpenChange = (open: boolean) => {
setPopoverOpen(open);
};
const { dashboardStore } = useStore();
const { dashboardStore, projectsStore } = useStore();
const siteId = projectsStore.activeSiteId
const [focusTitle, setFocusedInput] = React.useState(true);
const [showEditModal, setShowEditModal] = React.useState(false);
const period = dashboardStore.period;
@ -48,7 +49,7 @@ function DashboardHeader(props: Props) {
})
) {
dashboardStore.deleteDashboard(dashboard).then(() => {
props.history.push(withSiteId(`/dashboard`, siteId));
navigate(withSiteId(`/dashboard`, siteId));
});
}
};
@ -118,4 +119,4 @@ function DashboardHeader(props: Props) {
);
}
export default withRouter(withModal(observer(DashboardHeader)));
export default withModal(observer(DashboardHeader));

View file

@ -1,6 +1,6 @@
import { observer } from 'mobx-react-lite';
import React from 'react';
import { useHistory } from 'react-router';
import { useNavigate } from 'react-router';
import {
Empty,
Switch,
@ -32,7 +32,7 @@ function DashboardList() {
const list = dashboardStore.filteredList;
const dashboardsSearch = dashboardStore.filter.query;
const history = useHistory();
const navigate = useNavigate();
// Define custom width and height for each scenario
const searchImageDimensions = { width: 60, height: 'auto' };
@ -250,7 +250,7 @@ function DashboardList() {
dashboardSelected(record.dashboardId),
siteId
);
history.push(path);
navigate(path);
},
})}
/>

View file

@ -3,7 +3,7 @@ import withPageTitle from 'HOCs/withPageTitle';
import DashboardList from './DashboardList';
import Header from './Header';
function DashboardsView({history, siteId}: { history: any; siteId: string }) {
function DashboardsView() {
return (
<div style={{maxWidth: '1360px', margin: 'auto'}} className="bg-white rounded-lg py-4 border shadow-sm">
<Header />

View file

@ -1,108 +1,96 @@
import React from 'react';
import {Button, Space} from "antd";
import {ArrowLeft, ArrowRight} from "lucide-react";
import CardBuilder from "Components/Dashboard/components/WidgetForm/CardBuilder";
import {useHistory} from "react-router";
import {useStore} from "App/mstore";
import { HEATMAP } from "App/constants/card";
import {renderClickmapThumbnail} from "Components/Dashboard/components/WidgetForm/renderMap";
import WidgetPreview from "Components/Dashboard/components/WidgetPreview/WidgetPreview";
import { Button, Space } from 'antd';
import { ArrowLeft, ArrowRight } from 'lucide-react';
import { useNavigate, useLocation } from 'react-router';
import { useStore } from 'App/mstore';
import { HEATMAP } from 'App/constants/card';
import { renderClickmapThumbnail } from 'Components/Dashboard/components/WidgetForm/renderMap';
import WidgetPreview from 'Components/Dashboard/components/WidgetPreview/WidgetPreview';
import WidgetFormNew from 'Components/Dashboard/components/WidgetForm/WidgetFormNew';
const getTitleByType = (type: string) => {
switch (type) {
case HEATMAP:
return 'Heatmap';
default:
return 'Trend Single';
}
}
interface Props {
// cardType: string,
onBack?: () => void
onAdded?: () => void
extra?: React.ReactNode
onBack?: () => void;
onAdded?: () => void;
extra?: React.ReactNode;
}
function CreateCard(props: Props) {
const history = useHistory();
const {metricStore, dashboardStore, aiFiltersStore} = useStore();
const metric = metricStore.instance;
const siteId: string = history.location.pathname.split('/')[1];
const dashboardId: string = history.location.pathname.split('/')[3];
const isItDashboard = history.location.pathname.includes('dashboard')
// const title = getTitleByType(metric.metricType)
const location = useLocation();
const navigate = useNavigate();
const { metricStore, dashboardStore } = useStore();
const metric = metricStore.instance;
const dashboardId: string = location.pathname.split('/')[3];
const isItDashboard = location.pathname.includes('dashboard');
const createNewDashboard = async () => {
dashboardStore.initDashboard();
return await dashboardStore
.save(dashboardStore.dashboardInstance)
.then(async (syncedDashboard) => {
dashboardStore.selectDashboardById(syncedDashboard.dashboardId);
return syncedDashboard.dashboardId;
});
}
const createNewDashboard = async () => {
dashboardStore.initDashboard();
return await dashboardStore
.save(dashboardStore.dashboardInstance)
.then(async (syncedDashboard) => {
dashboardStore.selectDashboardById(syncedDashboard.dashboardId);
return syncedDashboard.dashboardId;
});
};
const addCardToDashboard = async (dashboardId: string, metricId: string) => {
return dashboardStore.addWidgetToDashboard(
dashboardStore.getDashboard(parseInt(dashboardId, 10))!, [metricId]
);
}
const createCard = async () => {
const isClickMap = metric.metricType === HEATMAP;
if (isClickMap) {
try {
metric.thumbnail = await renderClickmapThumbnail();
} catch (e) {
console.error(e);
}
}
const savedMetric = await metricStore.save(metric);
return savedMetric.metricId;
}
const createDashboardAndAddCard = async () => {
const cardId = await createCard();
if (dashboardId) {
await addCardToDashboard(dashboardId, cardId);
void dashboardStore.fetch(dashboardId);
props.onAdded?.();
} else if (isItDashboard) {
const dashboardId = await createNewDashboard();
await addCardToDashboard(dashboardId, cardId);
history.replace(`${history.location.pathname}/${dashboardId}`);
} else {
history.replace(`${history.location.pathname}/${cardId}`);
}
}
return (
<div className="flex gap-4 flex-col">
<div className="flex items-center justify-between">
<Space>
{props.onBack ? <Button type="text" onClick={props.onBack}>
<ArrowLeft size={16} />
</Button> : null}
<div className="text-xl leading-4 font-medium">
{metric.name}
</div>
</Space>
<Button type="primary" onClick={createDashboardAndAddCard}>
<Space>
Create <ArrowRight size={14}/>
</Space>
</Button>
</div>
{props.extra}
{/*<CardBuilder siteId={siteId}/>*/}
<WidgetFormNew/>
<WidgetPreview className="" name={metric.name} isEditing={true}/>
</div>
const addCardToDashboard = async (dashboardId: string, metricId: string) => {
return dashboardStore.addWidgetToDashboard(
dashboardStore.getDashboard(parseInt(dashboardId, 10))!,
[metricId]
);
};
const createCard = async () => {
const isClickMap = metric.metricType === HEATMAP;
if (isClickMap) {
try {
metric.thumbnail = await renderClickmapThumbnail();
} catch (e) {
console.error(e);
}
}
const savedMetric = await metricStore.save(metric);
return savedMetric.metricId;
};
const createDashboardAndAddCard = async () => {
const cardId = await createCard();
if (dashboardId) {
await addCardToDashboard(dashboardId, cardId);
void dashboardStore.fetch(dashboardId);
props.onAdded?.();
} else if (isItDashboard) {
const dashboardId = await createNewDashboard();
await addCardToDashboard(dashboardId, cardId);
navigate(`${location.pathname}/${dashboardId}`, { replace: true });
} else {
navigate(`${location.pathname}/${cardId}`, { replace: true });
}
};
return (
<div className="flex gap-4 flex-col">
<div className="flex items-center justify-between">
<Space>
{props.onBack ? (
<Button type="text" onClick={props.onBack}>
<ArrowLeft size={16} />
</Button>
) : null}
<div className="text-xl leading-4 font-medium">{metric.name}</div>
</Space>
<Button type="primary" onClick={createDashboardAndAddCard}>
<Space>
Create <ArrowRight size={14} />
</Space>
</Button>
</div>
{props.extra}
<WidgetFormNew />
<WidgetPreview className="" name={metric.name} isEditing={true} />
</div>
);
}
export default CreateCard;

View file

@ -1,13 +1,13 @@
import React, { useMemo, useState, useEffect } from 'react';
import { Button, Input, Segmented, Space } from 'antd';
import { RightOutlined } from '@ant-design/icons';
import { ArrowRight, Info } from 'lucide-react';
import { Info } from 'lucide-react';
import { CARD_LIST, CARD_CATEGORIES, CardType } from './ExampleCards';
import { useStore } from 'App/mstore';
import Option from './Option';
import CardsLibrary from 'Components/Dashboard/components/DashboardList/NewDashModal/CardsLibrary';
import { FUNNEL } from 'App/constants/card';
import { useHistory } from 'react-router';
import { useNavigate } from 'react-router';
import { FilterKey } from 'Types/filter/filterType';
import FilterSeries from '@/mstore/types/filterSeries';
@ -32,7 +32,7 @@ const SelectCard: React.FC<SelectCardProps> = (props: SelectCardProps) => {
const isCreatingDashboard = !dashboardId && location.pathname.includes('dashboard');
const [dashboardCreating, setDashboardCreating] = useState<boolean>(false);
const [dashboardUpdating, setDashboardUpdating] = useState<boolean>(false);
const history = useHistory();
const navigate = useNavigate();
useEffect(() => {
if (dashboardId) {
@ -49,8 +49,7 @@ const SelectCard: React.FC<SelectCardProps> = (props: SelectCardProps) => {
.save(dashboardStore.dashboardInstance)
.then(async (syncedDashboard) => {
dashboardStore.selectDashboardById(syncedDashboard.dashboardId);
history.push(`/${siteId}/dashboard/${syncedDashboard.dashboardId}`);
//return syncedDashboard.dashboardId;
navigate(`/${siteId}/dashboard/${syncedDashboard.dashboardId}`);
}).finally(() => {
setDashboardCreating(false);
});

View file

@ -3,20 +3,20 @@ import { useObserver } from 'mobx-react-lite';
import DashboardMetricSelection from '../DashboardMetricSelection';
import DashboardForm from '../DashboardForm';
import { Button } from 'antd';
import { withRouter, RouteComponentProps } from 'react-router-dom';
import { useStore } from 'App/mstore';
import { useModal } from 'App/components/Modal';
import { dashboardMetricCreate, withSiteId } from 'App/routes';
import { useNavigate } from "react-router";
interface Props extends RouteComponentProps {
history: any
siteId?: string
interface Props {
dashboardId?: string
onMetricAdd?: () => void;
}
function DashboardModal(props: Props) {
const { history, siteId, dashboardId } = props;
const { dashboardStore } = useStore();
const navigate = useNavigate();
const { dashboardId } = props;
const { dashboardStore, projectsStore } = useStore();
const siteId = projectsStore.activeSiteId
const selectedWidgetsCount = useObserver(() => dashboardStore.selectedWidgets.length);
const { hideModal } = useModal();
const dashboard = useObserver(() => dashboardStore.dashboardInstance);
@ -28,7 +28,7 @@ function DashboardModal(props: Props) {
await dashboardStore.fetch(dashboard.dashboardId)
}
dashboardStore.selectDashboardById(syncedDashboard.dashboardId);
history.push(withSiteId(`/dashboard/${syncedDashboard.dashboardId}`, siteId))
navigate(withSiteId(`/dashboard/${syncedDashboard.dashboardId}`, siteId))
})
.then(hideModal)
}
@ -36,7 +36,7 @@ function DashboardModal(props: Props) {
const handleCreateNew = () => {
const path = withSiteId(dashboardMetricCreate(dashboardId), siteId);
props.onMetricAdd();
history.push(path);
navigate(path);
hideModal();
}
const isDashboardExists = dashboard.exists()
@ -81,4 +81,4 @@ function DashboardModal(props: Props) {
));
}
export default withRouter(DashboardModal);
export default DashboardModal;

View file

@ -1,6 +1,5 @@
import React from 'react';
import { Switch, Route } from 'react-router';
import { withRouter, RouteComponentProps } from 'react-router-dom';
import { Routes, Route } from 'react-router';
import {
metrics,
@ -22,26 +21,18 @@ import WidgetSubDetailsView from '../WidgetSubDetailsView';
import DashboardsView from '../DashboardList';
import Alerts from '../Alerts';
import CreateAlert from '../Alerts/NewAlert'
import { useParams, useNavigate } from "react-router";
function DashboardViewSelected({ siteId, dashboardId }: { siteId: string; dashboardId: string }) {
return <DashboardView siteId={siteId} dashboardId={dashboardId} />;
}
interface Props extends RouteComponentProps {
match: any;
}
function DashboardRouter(props: Props) {
const {
match: {
params: { siteId, dashboardId },
},
history,
} = props;
function DashboardRouter(props: any) {
const { siteId, dashboardId } = useParams();
return (
<div>
<Switch>
<Routes>
<Route exact strict path={withSiteId(metrics(), siteId)}>
<MetricsView siteId={siteId} />
</Route>
@ -55,7 +46,7 @@ function DashboardRouter(props: Props) {
</Route>
<Route exact path={withSiteId(dashboard(), siteId)}>
<DashboardsView siteId={siteId} history={history} />
<DashboardsView siteId={siteId} />
</Route>
<Route exact strict path={withSiteId(dashboardMetricDetails(dashboardId), siteId)}>
@ -83,9 +74,9 @@ function DashboardRouter(props: Props) {
{/* @ts-ignore */}
<CreateAlert siteId={siteId} {...props} />
</Route>
</Switch>
</Routes>
</div>
);
}
export default withRouter(DashboardRouter);
export default DashboardRouter;

View file

@ -1,20 +1,21 @@
import React from 'react';
import { SideMenuitem } from 'UI';
import { withRouter, RouteComponentProps } from 'react-router-dom';
import { withSiteId, metrics, dashboard, alerts } from 'App/routes';
import { useLocation, useNavigate } from "react-router";
interface Props extends RouteComponentProps {
interface Props {
siteId: string;
history: any;
}
function DashboardSideMenu(props: Props) {
const { history, siteId } = props;
const isMetric = history.location.pathname.includes('metrics');
const isDashboards = history.location.pathname.includes('dashboard');
const isAlerts = history.location.pathname.includes('alerts');
const { siteId } = props;
const navigate = useNavigate();
const location = useLocation();
const isMetric = location.pathname.includes('metrics');
const isDashboards = location.pathname.includes('dashboard');
const isAlerts = location.pathname.includes('alerts');
const redirect = (path: string) => {
history.push(path);
navigate(path);
};
return (
@ -53,4 +54,4 @@ function DashboardSideMenu(props: Props) {
);
}
export default withRouter(DashboardSideMenu);
export default DashboardSideMenu;

View file

@ -5,29 +5,28 @@ import {Loader} from 'UI';
import {withSiteId} from 'App/routes';
import withModal from 'App/components/Modal/withModal';
import DashboardWidgetGrid from '../DashboardWidgetGrid';
import {withRouter, RouteComponentProps} from 'react-router-dom';
import {useModal} from 'App/components/Modal';
import DashboardModal from '../DashboardModal';
import AlertFormModal from 'App/components/Alerts/AlertFormModal';
import withPageTitle from 'HOCs/withPageTitle';
import withReport from 'App/components/hocs/withReport';
import DashboardHeader from '../DashboardHeader';
import {useHistory} from "react-router";
import { useNavigate } from "react-router";
import AiQuery from "./AiQuery";
interface IProps {
siteId: string;
dashboardId: any;
renderReport?: any;
}
type Props = IProps & RouteComponentProps;
type Props = IProps;
function DashboardView(props: Props) {
const {siteId, dashboardId} = props;
const {dashboardStore} = useStore();
const { dashboardId } = props;
const { dashboardStore, projectsStore } = useStore();
const siteId = projectsStore.activeSiteId;
const {showModal, hideModal} = useModal();
const history = useHistory();
const navigate = useNavigate();
const showAlertModal = dashboardStore.showAlertModal;
const loading = dashboardStore.fetchingDashboard;
@ -38,9 +37,8 @@ function DashboardView(props: Props) {
const trimQuery = () => {
if (!queryParams.has('modal')) return;
queryParams.delete('modal');
history.replace({
search: queryParams.toString(),
});
const search = queryParams.toString();
navigate(location.pathname + "?" + search, { replace: true });
};
useEffect(() => {
@ -60,7 +58,7 @@ function DashboardView(props: Props) {
}, [showAlertModal])
const pushQuery = () => {
if (!queryParams.has('modal')) history.push('?modal=addMetric');
if (!queryParams.has('modal')) navigate('?modal=addMetric');
};
useEffect(() => {
@ -75,7 +73,7 @@ function DashboardView(props: Props) {
useEffect(() => {
const isExists = dashboardStore.getDashboardById(dashboardId);
if (!isExists) {
history.push(withSiteId(`/dashboard`, siteId));
navigate(withSiteId(`/dashboard`, siteId));
}
}, [dashboardId]);

View file

@ -6,18 +6,18 @@ import WidgetWrapper from 'App/components/Dashboard/components/WidgetWrapper';
import { useStore } from 'App/mstore';
import { useModal } from 'App/components/Modal';
import { dashboardMetricCreate, withSiteId } from 'App/routes';
import { withRouter, RouteComponentProps } from 'react-router-dom';
import { useNavigate } from "react-router";
interface IProps extends RouteComponentProps {
siteId: string;
interface IProps {
title: string;
description: string;
}
function AddMetric({ history, siteId, title, description }: IProps) {
function AddMetric({ title, description }: IProps) {
const [metrics, setMetrics] = React.useState<Record<string, any>[]>([]);
const { dashboardStore } = useStore();
const navigate = useNavigate();
const { dashboardStore, projectsStore } = useStore();
const siteId = projectsStore.activeSiteId
const { hideModal } = useModal();
React.useEffect(() => {
@ -47,8 +47,8 @@ function AddMetric({ history, siteId, title, description }: IProps) {
const onCreateNew = () => {
const path = withSiteId(dashboardMetricCreate(dashboard.dashboardId), siteId);
if (!queryParams.has('modal')) history.push('?modal=addMetric');
history.push(path);
if (!queryParams.has('modal')) navigate('?modal=addMetric');
navigate(path);
hideModal();
};
@ -110,4 +110,4 @@ function AddMetric({ history, siteId, title, description }: IProps) {
);
}
export default withRouter(observer(AddMetric));
export default observer(AddMetric);

View file

@ -6,18 +6,19 @@ import WidgetWrapper from 'App/components/Dashboard/components/WidgetWrapper';
import { useStore } from 'App/mstore';
import { useModal } from 'App/components/Modal';
import { dashboardMetricCreate, withSiteId } from 'App/routes';
import { withRouter, RouteComponentProps } from 'react-router-dom';
import { WidgetCategoryItem } from 'App/components/Dashboard/components/DashboardMetricSelection/DashboardMetricSelection';
import { useNavigate } from "react-router";
interface IProps extends RouteComponentProps {
siteId: string;
interface IProps {
title: string;
description: string;
}
function AddPredefinedMetric({ history, siteId, title, description }: IProps) {
function AddPredefinedMetric({ title, description }: IProps) {
const navigate = useNavigate();
const [categories, setCategories] = React.useState([]);
const { dashboardStore } = useStore();
const { dashboardStore, projectsStore } = useStore();
const siteId = projectsStore.activeSiteId
const { hideModal } = useModal();
const [activeCategory, setActiveCategory] = React.useState<Record<string, any>>();
@ -62,8 +63,8 @@ function AddPredefinedMetric({ history, siteId, title, description }: IProps) {
const onCreateNew = () => {
const path = withSiteId(dashboardMetricCreate(dashboard.dashboardId), siteId);
if (!queryParams.has('modal')) history.push('?modal=addMetric');
history.push(path);
if (!queryParams.has('modal')) navigate('?modal=addMetric');
navigate(path);
hideModal();
};
@ -155,4 +156,4 @@ function AddPredefinedMetric({ history, siteId, title, description }: IProps) {
);
}
export default withRouter(observer(AddPredefinedMetric));
export default observer(AddPredefinedMetric);

View file

@ -2,7 +2,6 @@ import { Table, Typography } from 'antd';
import type { TableProps } from 'antd';
import { useObserver } from 'mobx-react-lite';
import React, { useEffect } from 'react';
import { RouteComponentProps, withRouter } from 'react-router-dom';
import { useModal } from 'App/components/Modal';
import { useStore } from 'App/mstore';
@ -10,8 +9,8 @@ import { NoContent } from 'UI';
import { InfoCircleOutlined } from '@ant-design/icons';
import AnimatedSVG, { ICONS } from 'Shared/AnimatedSVG/AnimatedSVG';
import FunnelIssueModal from '../FunnelIssueModal';
import FunnelIssuesListItem from '../FunnelIssuesListItem';
const { Text } = Typography;
import { useLocation, useNavigate } from "react-router";
interface Issue {
issueId: string;
@ -70,26 +69,25 @@ const columns: TableProps<Issue>['columns'] = [
},
];
interface Props extends RouteComponentProps {
interface Props {
loading?: boolean;
issues: Issue[];
history: any;
location: any;
}
function FunnelIssuesList(props: Props) {
const { issues, loading } = props;
const location = useLocation();
const navigate = useNavigate();
const { funnelStore } = useStore();
const issuesSort = useObserver(() => funnelStore.issuesSort);
const issuesFilter = useObserver(() =>
funnelStore.issuesFilter.map((issue: any) => issue.value)
);
const { showModal } = useModal();
const issueId = new URLSearchParams(props.location.search).get('issueId');
const issueId = new URLSearchParams(location.search).get('issueId');
const onIssueClick = (issue: any) => {
props.history.replace({
search: new URLSearchParams({ issueId: issue.issueId }).toString(),
});
const search = new URLSearchParams({ issueId: issue.issueId }).toString();
navigate(location.pathname + '?' + search, { replace: true });
};
useEffect(() => {
@ -99,8 +97,8 @@ function FunnelIssuesList(props: Props) {
right: true,
width: 1000,
onClose: () => {
if (props.history.location.pathname.includes('/metric')) {
props.history.replace({ search: '' });
if (location.pathname.includes('/metric')) {
navigate(location.pathname, { replace: true });
}
},
});
@ -147,4 +145,4 @@ function FunnelIssuesList(props: Props) {
));
}
export default withRouter(FunnelIssuesList);
export default FunnelIssuesList;

View file

@ -21,7 +21,7 @@ import { TYPE_ICONS, TYPE_NAMES } from 'App/constants/card';
import { useStore } from 'App/mstore';
import { observer } from 'mobx-react-lite';
import { toast } from 'react-toastify';
import { useHistory } from 'react-router';
import { useNavigate } from 'react-router';
import { EllipsisVertical } from 'lucide-react';
import cn from 'classnames'
@ -61,7 +61,7 @@ const MetricListItem: React.FC<Props> = ({
renderColumn,
inLibrary,
}) => {
const history = useHistory();
const navigate = useNavigate();
const { metricStore } = useStore();
const [isEdit, setIsEdit] = useState(false);
const [newName, setNewName] = useState(metric.name);
@ -75,7 +75,7 @@ const MetricListItem: React.FC<Props> = ({
return toggleSelection(e);
}
const path = withSiteId(`/metrics/${metric.metricId}`, siteId);
history.push(path);
navigate(path);
};
const onMenuClick = async ({ key }: { key: string }) => {
@ -99,7 +99,7 @@ const MetricListItem: React.FC<Props> = ({
try {
metric.update({ name: newName });
await metricStore.save(metric);
metricStore.fetchList();
void metricStore.fetchList();
setIsEdit(false);
} catch (e) {
toast.error('Failed to rename card');

View file

@ -3,21 +3,22 @@ import React from 'react';
import MetricsLibraryModal from '../MetricsLibraryModal';
import MetricTypeItem, { MetricType } from '../MetricTypeItem/MetricTypeItem';
import { TYPES, LIBRARY, INSIGHTS } from 'App/constants/card';
import { withRouter, RouteComponentProps } from 'react-router-dom';
import { dashboardMetricCreate, metricCreate, withSiteId } from 'App/routes';
import { useStore } from 'App/mstore';
import { observer } from 'mobx-react-lite';
import { ENTERPRISE_REQUEIRED } from 'App/constants';
import { useNavigate } from "react-router";
interface Props extends RouteComponentProps {
interface Props {
dashboardId?: number;
siteId: string;
isList?: boolean;
}
function MetricTypeList(props: Props) {
const { dashboardId, siteId, history, isList = false } = props;
const { metricStore, userStore } = useStore();
const navigate = useNavigate();
const { dashboardId, isList = false } = props;
const { metricStore, userStore, projectsStore } = useStore();
const siteId = projectsStore.activeSiteId;
const { showModal, hideModal } = useModal();
const isEnterprise = userStore.isEnterprise;
@ -49,13 +50,11 @@ function MetricTypeList(props: Props) {
});
}
const path = dashboardId ? withSiteId(dashboardMetricCreate(dashboardId + ''), siteId) :
withSiteId(metricCreate(), siteId);
const path = dashboardId
? withSiteId(dashboardMetricCreate(dashboardId + ''), siteId)
: withSiteId(metricCreate(), siteId);
const queryString = new URLSearchParams({ type: slug }).toString();
history.push({
pathname: path,
search: `?${queryString}`
});
navigate(path + `?${queryString}`);
};
return (
@ -67,4 +66,4 @@ function MetricTypeList(props: Props) {
);
}
export default withRouter(observer(MetricTypeList));
export default observer(MetricTypeList);

View file

@ -1,18 +1,20 @@
import React from 'react';
import WidgetWrapper from 'App/components/Dashboard/components/WidgetWrapper';
import { withRouter, RouteComponentProps } from 'react-router-dom';
import { withSiteId } from 'App/routes';
interface Props extends RouteComponentProps {
import { useNavigate } from "react-router";
interface Props {
list: any;
siteId: any;
selectedList: any;
}
function GridView(props: Props) {
const { siteId, list, selectedList, history } = props;
const { siteId, list, selectedList } = props;
const navigate = useNavigate();
const onItemClick = (metricId: number) => {
const path = withSiteId(`/metrics/${metricId}`, siteId);
history.push(path);
navigate(path);
};
return (
@ -33,4 +35,4 @@ function GridView(props: Props) {
);
}
export default withRouter(GridView);
export default GridView;

View file

@ -15,7 +15,7 @@ import { EllipsisVertical } from 'lucide-react';
import { TablePaginationConfig, SorterResult } from 'antd/lib/table/interface';
import { useStore } from 'App/mstore';
import { toast } from 'react-toastify';
import { useHistory } from 'react-router';
import { useNavigate } from 'react-router';
import { withSiteId } from 'App/routes';
import { Icon } from 'UI';
import cn from 'classnames';
@ -49,7 +49,7 @@ const ListView: React.FC<Props> = ({
const [editingMetricId, setEditingMetricId] = useState<number | null>(null);
const [newName, setNewName] = useState('');
const { metricStore } = useStore();
const history = useHistory();
const navigate = useNavigate();
const sortedData = useMemo(() => {
return [...list].sort((a, b) => {
@ -142,7 +142,7 @@ const ListView: React.FC<Props> = ({
const onItemClick = (metric: Widget) => {
if (disableSelection) {
const path = withSiteId(`/metrics/${metric.metricId}`, siteId);
history.push(path);
navigate(path);
} else {
toggleSelection?.(metric.metricId);
}

View file

@ -17,7 +17,7 @@ import FilterItem from 'Shared/Filters/FilterItem';
import {
TIMESERIES, TABLE, HEATMAP, FUNNEL, ERRORS, INSIGHTS, USER_PATH, RETENTION
} from 'App/constants/card';
import {useHistory} from "react-router";
import { useNavigate } from "react-router";
const tableOptions = metricOf.filter((i) => i.type === 'table');
@ -217,8 +217,8 @@ interface CardBuilderProps {
}
const CardBuilder = observer((props: CardBuilderProps) => {
const history = useHistory();
const {siteId, dashboardId, metricId} = props;
const navigate = useNavigate();
const { siteId, dashboardId, metricId } = props;
const {metricStore, dashboardStore, aiFiltersStore} = useStore();
const [aiQuery, setAiQuery] = useState('');
const [aiAskChart, setAiAskChart] = useState('');
@ -259,7 +259,7 @@ const CardBuilder = observer((props: CardBuilderProps) => {
const route = parseInt(dashboardId, 10) > 0
? withSiteId(dashboardMetricDetails(dashboardId, savedMetric.metricId), siteId)
: withSiteId(metricDetails(savedMetric.metricId), siteId);
history.replace(route);
navigate(route, { replace: true });
if (parseInt(dashboardId, 10) > 0) {
dashboardStore.addWidgetToDashboard(
dashboardStore.getDashboard(parseInt(dashboardId, 10)),
@ -267,7 +267,7 @@ const CardBuilder = observer((props: CardBuilderProps) => {
);
}
}
}, [dashboardId, dashboardStore, history, metric, metricStore, siteId]);
}, [dashboardId, dashboardStore, metric, metricStore, siteId]);
const onDelete = useCallback(async () => {
if (await confirm({

View file

@ -1,4 +1,4 @@
import { useHistory } from 'react-router';
import { useNavigate } from 'react-router';
import { useStore } from 'App/mstore';
import { observer } from 'mobx-react-lite';
import { Button, Dropdown, MenuProps, Modal } from 'antd';
@ -10,7 +10,7 @@ import AlertFormModal from 'Components/Alerts/AlertFormModal/AlertFormModal';
import { showAddToDashboardModal } from 'Components/Dashboard/components/AddToDashboardButton';
const CardViewMenu = () => {
const history = useHistory();
const navigate = useNavigate();
const { alertsStore, metricStore, dashboardStore } = useStore();
const widget = metricStore.instance;
const { openModal, closeModal } = useModal();
@ -60,7 +60,7 @@ const CardViewMenu = () => {
metricStore
.delete(widget)
.then(() => {
history.goBack();
navigate(-1)
})
.catch(() => {
toast.error('Failed to remove card');

View file

@ -1,13 +1,13 @@
import React, { useState, useEffect } from 'react';
import { useStore } from 'App/mstore';
import { Loader } from 'UI';
import { Loader, NavPrompt } from 'UI';
import WidgetPreview from '../WidgetPreview';
import WidgetSessions from '../WidgetSessions';
import { observer } from 'mobx-react-lite';
import { dashboardMetricDetails, metricDetails, withSiteId } from 'App/routes';
import Breadcrumb from 'Shared/Breadcrumb';
import { FilterKey } from 'Types/filter/filterType';
import { Prompt, useHistory, useLocation } from 'react-router';
import { useNavigate, useLocation } from 'react-router';
import {
TIMESERIES,
TABLE,
@ -29,7 +29,6 @@ import { CARD_LIST, CardType } from 'Components/Dashboard/components/DashboardLi
import FilterSeries from '@/mstore/types/filterSeries';
interface Props {
history: any;
match: any;
siteId: any;
}
@ -50,7 +49,7 @@ function WidgetView({ match: { params: { siteId, dashboardId, metricId } } }: Pr
const dashboard = dashboardStore.dashboards.find((d: any) => d.dashboardId == dashboardId);
const dashboardName = dashboard ? dashboard.name : null;
const [metricNotFound, setMetricNotFound] = useState(false);
const history = useHistory();
const navigate = useNavigate();
const location = useLocation();
const [initialInstance, setInitialInstance] = useState();
const isClickMap = widget.metricType === HEATMAP;
@ -112,9 +111,9 @@ function WidgetView({ match: { params: { siteId, dashboardId, metricId } } }: Pr
useEffect(() => {
if (metricNotFound) {
history.replace(withSiteId('/metrics', siteId));
navigate(withSiteId('/metrics', siteId), { replace: true });
}
}, [metricNotFound, history, siteId]);
}, [metricNotFound, siteId]);
const undoChanges = () => {
const w = new Widget();
@ -134,15 +133,15 @@ function WidgetView({ match: { params: { siteId, dashboardId, metricId } } }: Pr
setInitialInstance(widget.toJson());
if (wasCreating) {
if (parseInt(dashboardId, 10) > 0) {
history.replace(
navigate(
withSiteId(dashboardMetricDetails(dashboardId, savedMetric.metricId), siteId)
);
, { replace: true });
void dashboardStore.addWidgetToDashboard(
dashboardStore.getDashboard(parseInt(dashboardId, 10))!,
[savedMetric.metricId]
);
} else {
history.replace(withSiteId(metricDetails(savedMetric.metricId), siteId));
navigate(withSiteId(metricDetails(savedMetric.metricId), siteId), { replace: true });
}
}
};
@ -154,7 +153,7 @@ function WidgetView({ match: { params: { siteId, dashboardId, metricId } } }: Pr
return (
<Loader loading={loading}>
<Prompt
<NavPrompt
when={hasChanged}
message={(loc: any) =>
loc.pathname.includes('/metrics/') || loc.pathname.includes('/metric/')

View file

@ -1,48 +1,48 @@
import React from 'react';
import {useHistory} from "react-router";
import {useStore} from "App/mstore";
import {useObserver} from "mobx-react-lite";
import {Button, Dropdown, MenuProps, message, Modal} from "antd";
import {BellIcon, EllipsisVertical, EyeOffIcon, PencilIcon, TrashIcon} from "lucide-react";
import {toast} from "react-toastify";
import {dashboardMetricDetails, withSiteId} from "App/routes";
import { useNavigate } from 'react-router';
import { useStore } from 'App/mstore';
import { Button, Dropdown, MenuProps } from 'antd';
import { EllipsisVertical, EyeOffIcon, PencilIcon } from 'lucide-react';
import { dashboardMetricDetails, withSiteId } from 'App/routes';
function CardMenu({card}: any) {
const siteId = location.pathname.split('/')[1];
const history = useHistory();
const {dashboardStore, metricStore} = useStore();
const dashboardId = dashboardStore.selectedDashboard?.dashboardId;
function CardMenu({ card }: any) {
const siteId = location.pathname.split('/')[1];
const navigate = useNavigate();
const { dashboardStore } = useStore();
const dashboardId = dashboardStore.selectedDashboard?.dashboardId;
const items: MenuProps['items'] = [
{
key: 'edit',
label: "Edit",
icon: <PencilIcon size={16}/>,
},
{
key: 'hide',
label: 'Remove from Dashboard',
icon: <EyeOffIcon size={16}/>,
},
];
const items: MenuProps['items'] = [
{
key: 'edit',
label: 'Edit',
icon: <PencilIcon size={16} />,
},
{
key: 'hide',
label: 'Remove from Dashboard',
icon: <EyeOffIcon size={16} />,
},
];
const onClick: MenuProps['onClick'] = ({key}) => {
if (key === 'edit') {
history.push(
withSiteId(dashboardMetricDetails(dashboardId, card.metricId), siteId)
)
} else if (key === 'hide') {
dashboardStore.deleteDashboardWidget(dashboardId!, card.widgetId).then(r => null);
}
};
const onClick: MenuProps['onClick'] = ({ key }) => {
if (key === 'edit') {
navigate(
withSiteId(dashboardMetricDetails(dashboardId, card.metricId), siteId)
);
} else if (key === 'hide') {
dashboardStore
.deleteDashboardWidget(dashboardId!, card.widgetId)
.then((r) => null);
}
};
return (
<div className="flex items-center justify-between">
<Dropdown menu={{items, onClick}} overlayStyle={{minWidth: '120px'}}>
<Button type="text" icon={<EllipsisVertical size={16}/>}/>
</Dropdown>
</div>
);
return (
<div className="flex items-center justify-between">
<Dropdown menu={{ items, onClick }} overlayStyle={{ minWidth: '120px' }}>
<Button type="text" icon={<EllipsisVertical size={16} />} />
</Dropdown>
</div>
);
}
export default CardMenu;

View file

@ -1,14 +1,14 @@
import React, { useRef, lazy } from 'react';
import cn from 'classnames';
import { ItemMenu, TextEllipsis } from 'UI';
import { TextEllipsis } from 'UI';
import { useDrag, useDrop } from 'react-dnd';
import { observer } from 'mobx-react-lite';
import { useStore } from 'App/mstore';
import { withRouter, RouteComponentProps } from 'react-router-dom';
import { withSiteId, dashboardMetricDetails } from 'App/routes';
import TemplateOverlay from './TemplateOverlay';
import { FilterKey } from 'App/types/filter/filterType';
import { TIMESERIES } from 'App/constants/card';
import { useNavigate } from "react-router";
const WidgetChart = lazy(
() => import('Components/Dashboard/components/WidgetChart')
@ -22,17 +22,17 @@ interface Props {
isPreview?: boolean;
isTemplate?: boolean;
dashboardId?: string;
siteId?: string;
active?: boolean;
history?: any;
onClick?: () => void;
isSaved?: boolean;
hideName?: boolean;
grid?: string;
isGridView?: boolean;
}
function WidgetWrapper(props: Props & RouteComponentProps) {
const { dashboardStore } = useStore();
function WidgetWrapper(props: Props) {
const { dashboardStore, projectsStore } = useStore();
const siteId = projectsStore.activeSiteId;
const navigate = useNavigate();
const {
isSaved = false,
active = false,
@ -40,7 +40,6 @@ function WidgetWrapper(props: Props & RouteComponentProps) {
moveListItem = null,
isPreview = false,
isTemplate = false,
siteId,
grid = '',
isGridView = false,
} = props;
@ -83,7 +82,7 @@ function WidgetWrapper(props: Props & RouteComponentProps) {
const onChartClick = () => {
if (!isSaved || isPredefined) return;
props.history.push(
navigate(
withSiteId(
dashboardMetricDetails(dashboard?.dashboardId, widget.metricId),
siteId
@ -150,4 +149,4 @@ function WidgetWrapper(props: Props & RouteComponentProps) {
);
}
export default withRouter(observer(WidgetWrapper));
export default observer(WidgetWrapper);

View file

@ -4,8 +4,8 @@ import { Card, Tooltip } from 'antd';
import { useDrag, useDrop } from 'react-dnd';
import { observer } from 'mobx-react-lite';
import { useStore } from 'App/mstore';
import { withRouter, RouteComponentProps } from 'react-router-dom';
import { withSiteId, dashboardMetricDetails } from 'App/routes';
import { useNavigate } from "react-router";
import TemplateOverlay from './TemplateOverlay';
import stl from './widgetWrapper.module.css';
import { FilterKey } from 'App/types/filter/filterType';
@ -25,7 +25,6 @@ interface Props {
dashboardId?: string;
siteId?: string;
active?: boolean;
history?: any;
onClick?: () => void;
isWidget?: boolean;
hideName?: boolean;
@ -35,8 +34,10 @@ interface Props {
isSaved?: boolean;
}
function WidgetWrapperNew(props: Props & RouteComponentProps) {
const { dashboardStore, metricStore } = useStore();
function WidgetWrapperNew(props: Props) {
const navigate = useNavigate()
const { dashboardStore, metricStore, projectsStore } = useStore();
const siteId = projectsStore.activeSiteId;
const {
isWidget = false,
active = false,
@ -44,7 +45,6 @@ function WidgetWrapperNew(props: Props & RouteComponentProps) {
moveListItem = null,
isPreview = false,
isTemplate = false,
siteId,
grid = '',
isGridView = false,
showMenu = false,
@ -80,7 +80,7 @@ function WidgetWrapperNew(props: Props & RouteComponentProps) {
const onChartClick = () => {
// if (!isWidget || isPredefined) return;
props.history.push(
navigate(
withSiteId(dashboardMetricDetails(dashboard?.dashboardId, widget.metricId), siteId)
);
};
@ -164,4 +164,4 @@ function WidgetWrapperNew(props: Props & RouteComponentProps) {
);
}
export default withRouter(observer(WidgetWrapperNew));
export default observer(WidgetWrapperNew);

View file

@ -3,8 +3,7 @@ import { FilterKey } from 'Types/filter/filterType';
import cn from 'classnames';
import { observer } from 'mobx-react-lite';
import React from 'react';
import { withRouter } from 'react-router-dom';
import { useNavigate } from 'react-router'
import { resentOrDate } from 'App/date';
import { useStore } from 'App/mstore';
import { sessions as sessionsRoute } from 'App/routes';
@ -17,6 +16,7 @@ import { Button } from 'antd'
import SessionBar from './SessionBar';
function MainSection(props) {
const navigate = useNavigate();
const { errorStore, searchStore } = useStore();
const error = errorStore.instance;
const trace = errorStore.instanceTrace;
@ -26,7 +26,7 @@ function MainSection(props) {
const findSessions = () => {
searchStore.addFilterByKeyAndValue(FilterKey.ERROR, error.message);
props.history.push(sessionsRoute());
navigate(sessionsRoute());
};
return (
<div
@ -129,6 +129,4 @@ function MainSection(props) {
);
}
export default withRouter(
(observer(MainSection))
);
export default observer(MainSection)

View file

@ -2,11 +2,11 @@ import React from 'react'
import { PageTitle } from 'UI'
import { Button } from 'antd'
import FFlagsSearch from "Components/FFlags/FFlagsSearch";
import { useHistory } from "react-router";
import { useNavigate } from "react-router";
import { newFFlag, withSiteId } from 'App/routes';
function FFlagsListHeader({ siteId }: { siteId: string }) {
const history = useHistory();
const navigate = useNavigate();
return (
<div className="flex items-center justify-between px-6">
@ -14,7 +14,7 @@ function FFlagsListHeader({ siteId }: { siteId: string }) {
<PageTitle title="Feature Flags" />
</div>
<div className="ml-auto flex items-center">
<Button type="primary" onClick={() => history.push(withSiteId(newFFlag(), siteId))}>
<Button type="primary" onClick={() => navigate(withSiteId(newFFlag(), siteId))}>
Create Feature Flag
</Button>
<div className="mx-2"></div>

View file

@ -4,7 +4,7 @@ import { useStore } from 'App/mstore';
import { Loader, NoContent, ItemMenu } from 'UI';
import { Button, Switch } from 'antd'
import Breadcrumb from 'Shared/Breadcrumb';
import { useHistory } from 'react-router';
import { useNavigate } from 'react-router';
import { withSiteId, fflag, fflags } from 'App/routes';
import Multivariant from "Components/FFlags/NewFFlag/Multivariant";
import { toast } from 'react-toastify';
@ -12,7 +12,7 @@ import RolloutCondition from "Shared/ConditionSet";
function FlagView({ siteId, fflagId }: { siteId: string; fflagId: string }) {
const { featureFlagsStore } = useStore();
const history = useHistory();
const navigate = useNavigate();
React.useEffect(() => {
if (fflagId) {
@ -27,7 +27,7 @@ function FlagView({ siteId, fflagId }: { siteId: string; fflagId: string }) {
const deleteHandler = () => {
featureFlagsStore.deleteFlag(current.featureFlagId).then(() => {
toast.success('Feature flag deleted.');
history.push(withSiteId(fflags(), siteId));
navigate(withSiteId(fflags(), siteId));
});
};
@ -63,7 +63,7 @@ function FlagView({ siteId, fflagId }: { siteId: string; fflagId: string }) {
className={'ml-auto text-main'}
type={'text'}
onClick={() =>
history.push(
navigate(
withSiteId(
fflag(
featureFlagsStore.currentFflag?.featureFlagId.toString()

View file

@ -3,19 +3,19 @@ import { observer } from 'mobx-react-lite';
import cn from 'classnames';
import { ItemMenu } from 'UI';
import { useStore } from 'App/mstore';
import { useHistory } from 'react-router';
import { useNavigate } from 'react-router';
import { toast } from 'react-toastify';
import { fflags, withSiteId } from "App/routes";
import { Button } from 'antd';
function Header({ current, onCancel, onSave, isNew, siteId }: any) {
const { featureFlagsStore } = useStore();
const history = useHistory();
const navigate = useNavigate()
const deleteHandler = () => {
featureFlagsStore.deleteFlag(current.featureFlagId).then(() => {
toast.success('Feature flag deleted.');
history.push(withSiteId(fflags(), siteId));
navigate(withSiteId(fflags(), siteId));
});
};

View file

@ -1,12 +1,12 @@
import React from 'react';
import { observer } from 'mobx-react-lite';
import { useStore } from 'App/mstore';
import { Input, SegmentSelection, Loader, NoContent } from 'UI';
import { Input, SegmentSelection, Loader, NoContent, NavPrompt } from 'UI';
import Breadcrumb from 'Shared/Breadcrumb';
import { Button, Switch } from 'antd'
import { useModal } from 'App/components/Modal';
import HowTo from 'Components/FFlags/NewFFlag/HowTo';
import {Prompt, useHistory} from 'react-router';
import { useNavigate } from 'react-router';
import {withSiteId, fflags, fflagRead} from 'App/routes';
import Description from './Description';
import Header from './Header';
@ -32,7 +32,7 @@ function NewFFlag({ siteId, fflagId }: { siteId: string; fflagId?: string }) {
const current = featureFlagsStore.currentFflag;
const { showModal } = useModal();
const history = useHistory();
const navigate = useNavigate()
if (featureFlagsStore.isLoading) return <Loader loading={true} />;
if (!current) return (
@ -52,7 +52,7 @@ function NewFFlag({ siteId, fflagId }: { siteId: string; fflagId?: string }) {
};
const onCancel = () => {
history.goBack()
navigate(-1)
};
const onSave = () => {
@ -61,7 +61,7 @@ function NewFFlag({ siteId, fflagId }: { siteId: string; fflagId?: string }) {
if (fflagId) {
featureFlagsStore.updateFlag().then(() => {
toast.success('Feature flag updated.');
history.push(withSiteId(fflagRead(fflagId), siteId));
navigate(withSiteId(fflagRead(fflagId), siteId));
})
.catch(() => {
toast.error(`Failed to update flag, check your data and try again.`)
@ -69,7 +69,7 @@ function NewFFlag({ siteId, fflagId }: { siteId: string; fflagId?: string }) {
} else {
featureFlagsStore.createFlag().then(() => {
toast.success('Feature flag created.');
history.push(withSiteId(fflags(), siteId));
navigate(withSiteId(fflags(), siteId));
}).catch(() => {
toast.error('Failed to create flag.');
})
@ -79,7 +79,7 @@ function NewFFlag({ siteId, fflagId }: { siteId: string; fflagId?: string }) {
const showDescription = Boolean(current.description?.length);
return (
<div className={'w-full mx-auto mb-4'} style={{ maxWidth: '1360px' }}>
<Prompt
<NavPrompt
when={current.hasChanged}
message={() => {
return 'You have unsaved changes. Are you sure you want to leave?';

View file

@ -1,13 +1,12 @@
import React from 'react';
import { Icon } from 'UI';
import { withRouter } from 'react-router-dom';
import { useNavigate } from "react-router";
interface Props {
history: any;
}
function PreferencesView(props: Props) {
function PreferencesView() {
const navigate = useNavigate();
const onExit = () => {
props.history.push('/');
navigate('/');
};
return (
<>
@ -24,4 +23,4 @@ function PreferencesView(props: Props) {
);
}
export default withRouter(PreferencesView);
export default PreferencesView;

View file

@ -1,39 +1,38 @@
import React from 'react';
import cn from 'classnames';
import { Icon } from 'UI';
import { CLIENT_TABS, client as clientRoute } from 'App/routes';
import { withRouter, RouteComponentProps } from 'react-router';
import { useNavigate } from "react-router";
interface Props {
history: any;
className: string;
account: any;
}
function SettingsMenu(props: RouteComponentProps<Props>) {
const { history, account, className }: any = props;
function SettingsMenu(props: Props) {
const navigate = useNavigate();
const { account, className }: any = props;
const isAdmin = account.admin || account.superAdmin;
const isEnterprise = account.edition === 'ee';
const navigateTo = (path: any) => {
switch (path) {
case 'sessions-listing':
return history.push(clientRoute(CLIENT_TABS.SESSIONS_LISTING));
return navigate(clientRoute(CLIENT_TABS.SESSIONS_LISTING));
case 'projects':
return history.push(clientRoute(CLIENT_TABS.SITES));
return navigate(clientRoute(CLIENT_TABS.SITES));
case 'team':
return history.push(clientRoute(CLIENT_TABS.MANAGE_USERS));
return navigate(clientRoute(CLIENT_TABS.MANAGE_USERS));
case 'metadata':
return history.push(clientRoute(CLIENT_TABS.CUSTOM_FIELDS));
return navigate(clientRoute(CLIENT_TABS.CUSTOM_FIELDS));
case 'webhooks':
return history.push(clientRoute(CLIENT_TABS.WEBHOOKS));
return navigate(clientRoute(CLIENT_TABS.WEBHOOKS));
case 'integrations':
return history.push(clientRoute(CLIENT_TABS.INTEGRATIONS));
return navigate(clientRoute(CLIENT_TABS.INTEGRATIONS));
case 'notifications':
return history.push(clientRoute(CLIENT_TABS.NOTIFICATIONS));
return navigate(clientRoute(CLIENT_TABS.NOTIFICATIONS));
case 'roles':
return history.push(clientRoute(CLIENT_TABS.MANAGE_ROLES));
return navigate(clientRoute(CLIENT_TABS.MANAGE_ROLES));
case 'audit':
return history.push(clientRoute(CLIENT_TABS.AUDIT));
return navigate(clientRoute(CLIENT_TABS.AUDIT));
}
};
return (
@ -64,7 +63,7 @@ function SettingsMenu(props: RouteComponentProps<Props>) {
);
}
export default withRouter(SettingsMenu);
export default SettingsMenu;
function MenuItem({ onClick, label, icon }: any) {
return (

View file

@ -1,24 +1,21 @@
import React from 'react';
import { withRouter } from 'react-router-dom';
import { client, CLIENT_DEFAULT_TAB } from 'App/routes';
import { Icon } from 'UI';
import { getInitials } from 'App/utils';
import { useStore } from "App/mstore";
import { observer } from 'mobx-react-lite';
import { useNavigate } from "react-router";
const CLIENT_PATH = client(CLIENT_DEFAULT_TAB);
interface Props {
history: any;
}
function UserMenu(props: Props) {
const { history }: any = props;
function UserMenu() {
const navigate = useNavigate();
const { loginStore, userStore } = useStore();
const account = userStore.account;
const onLogoutClick = userStore.logout;
const onAccountClick = () => {
history.push(CLIENT_PATH);
navigate(CLIENT_PATH);
};
const onLogout = () => {
@ -59,4 +56,4 @@ function UserMenu(props: Props) {
);
}
export default withRouter(observer(UserMenu))
export default observer(UserMenu)

View file

@ -12,11 +12,11 @@ import { toast } from 'react-toastify';
import EditHlModal from './EditHlModal';
import HighlightsListHeader from './HighlightsListHeader';
import withPermissions from 'HOCs/withPermissions';
import { useHistory } from 'react-router';
import { useNavigate } from 'react-router';
import { highlights, withSiteId } from 'App/routes'
function HighlightsList() {
const history = useHistory();
const navigate = useNavigate()
const params = new URLSearchParams(window.location.search);
const hlId = params.get('highlight');
const { notesStore, projectsStore, userStore } = useStore();
@ -31,7 +31,7 @@ function HighlightsList() {
React.useEffect(() => {
if (hlId) {
setActiveId(hlId);
history.replace(withSiteId(highlights(), projectsStore.siteId));
navigate(withSiteId(highlights(), projectsStore.siteId), { replace: true });
}
}, [hlId])

View file

@ -3,7 +3,7 @@ import cn from 'classnames';
import React, { useEffect, useRef, useState } from 'react';
// Consider using a different approach for titles in functional components
import ReCAPTCHA from 'react-google-recaptcha';
import { useHistory } from 'react-router-dom';
import { useNavigate, useLocation } from 'react-router';
import { observer } from 'mobx-react-lite';
import { toast } from 'react-toastify';
@ -20,13 +20,8 @@ import stl from './login.module.css';
const FORGOT_PASSWORD = forgotPassword();
const SIGNUP_ROUTE = signup();
interface LoginProps {
location: Location;
}
const Login = ({
location
}: LoginProps) => {
const Login = () => {
const location = useLocation()
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const CAPTCHA_ENABLED = React.useMemo(() => {
@ -38,12 +33,12 @@ const Login = ({
const loading = loginStore.loading;
const authDetails = userStore.authStore.authDetails;
const setJwt = userStore.updateJwt;
const history = useHistory();
const navigate = useNavigate()
const params = new URLSearchParams(location.search);
useEffect(() => {
if (authDetails && !authDetails.tenants) {
history.push(SIGNUP_ROUTE);
navigate(SIGNUP_ROUTE);
}
}, [authDetails]);

View file

@ -1,8 +1,7 @@
import React, { useEffect } from 'react';
import React from 'react';
import ReactDOM from 'react-dom';
import ModalOverlay from './ModalOverlay';
import cn from 'classnames';
import { useHistory } from 'react-router';
const DEFAULT_WIDTH = 350;
interface Props {
@ -13,16 +12,6 @@ interface Props {
width?: number;
}
function Modal({ component, className = 'bg-white', props, hideModal }: Props) {
const history = useHistory();
useEffect(() => {
return history.listen((location) => {
if (history.action === 'POP') {
document.querySelector('body').style.overflow = 'visible';
}
});
});
return component ? (
ReactDOM.createPortal(
<ModalOverlay hideModal={hideModal} left={!props.right} right={props.right}>

View file

@ -1,7 +1,6 @@
import React from 'react';
import { Redirect, Route, RouteComponentProps, Switch } from 'react-router';
import { withRouter } from 'react-router-dom';
import { Navigate, Route, Routes } from 'react-router';
import { useParams, useNavigate } from "react-router";
import { OB_TABS, onboarding as onboardingRoute } from 'App/routes';
import { withSiteId } from 'App/routes';
import { Icon } from 'UI';
@ -12,22 +11,14 @@ import IntegrationsTab from './components/IntegrationsTab';
import ManageUsersTab from './components/ManageUsersTab';
import SideMenu from './components/SideMenu';
interface Props {
match: {
params: {
activeTab: string;
siteId: string;
};
};
history: RouteComponentProps['history'];
}
const platformMap = {
ios: 'mobile',
web: 'web',
};
const Onboarding = (props: Props) => {
const Onboarding = (props) => {
const navigate = useNavigate();
const { activeTab, siteId } = useParams();
const platforms = [
{
label: (
@ -47,18 +38,13 @@ const Onboarding = (props: Props) => {
} as const,
] as const;
const [platform, setPlatform] = React.useState(platforms[0]);
const {
match: {
params: { activeTab, siteId },
},
} = props;
const route = (path: string) => {
return withSiteId(onboardingRoute(path));
};
const onMenuItemClick = (tab: string) => {
props.history.push(withSiteId(onboardingRoute(tab), siteId));
navigate(withSiteId(onboardingRoute(tab), siteId));
};
return (
@ -69,7 +55,7 @@ const Onboarding = (props: Props) => {
className="bg-white w-full rounded-lg mx-auto mb-8 border"
style={{ maxWidth: '1360px' }}
>
<Switch>
<Routes>
<Route exact strict path={route(OB_TABS.INSTALLING)}>
<InstallOpenReplayTab
platforms={platforms}
@ -98,17 +84,14 @@ const Onboarding = (props: Props) => {
path={route(OB_TABS.INTEGRATIONS)}
component={IntegrationsTab}
/>
<Redirect to={route(OB_TABS.INSTALLING)} />
</Switch>
<Route path={'*'}>
<Navigate to={route(OB_TABS.INSTALLING)} />
</Route>
</Routes>
</div>
</div>
{/* <div className="py-6 px-4 w-full flex items-center fixed bottom-0 bg-white border-t z-10">
<div className="ml-auto">
<OnboardingNavButton />
</div>
</div> */}
</div>
);
};
export default withRouter(Onboarding);
export default Onboarding;

View file

@ -1,10 +1,10 @@
import React from 'react';
import { Icon, SideMenuitem } from 'UI';
import { SideMenuitem } from 'UI';
import cn from 'classnames';
import stl from './onboardingMenu.module.css';
import { OB_TABS, onboarding as onboardingRoute } from 'App/routes';
import { withRouter } from 'react-router-dom';
import * as routes from '../../../../routes';
import * as routes from 'App/routes';
import { useParams, useNavigate } from "react-router";
const withSiteId = routes.withSiteId;
@ -15,7 +15,7 @@ const MENU_ITEMS = [
OB_TABS.INTEGRATIONS,
];
const Item = ({ icon, text, completed, active, onClick }) => (
const Item = ({ text, completed, active, onClick }) => (
<div
className={cn('cursor-pointer', stl.stepWrapper, {
[stl.completed]: completed,
@ -39,17 +39,14 @@ const Item = ({ icon, text, completed, active, onClick }) => (
</div>
);
const OnboardingMenu = (props) => {
const {
match: {
params: { activeTab, siteId },
},
history,
} = props;
const OnboardingMenu = () => {
const { siteId, activeTab } = useParams();
const navigate = useNavigate();
const activeIndex = MENU_ITEMS.findIndex((i) => i === activeTab);
const setTab = (tab) => {
history.push(withSiteId(onboardingRoute(tab), siteId));
navigate(withSiteId(onboardingRoute(tab), siteId));
};
return (
@ -61,28 +58,24 @@ const OnboardingMenu = (props) => {
<>
<Item
icon="check"
text="Install OpenReplay"
completed={activeIndex >= 0}
active={activeIndex === 0}
onClick={() => setTab(MENU_ITEMS[0])}
/>
<Item
icon="check"
text="Identify Users"
completed={activeIndex >= 1}
active={activeIndex === 1}
onClick={() => setTab(MENU_ITEMS[1])}
/>
<Item
icon="check"
text="Invite Collaborators"
completed={activeIndex >= 2}
active={activeIndex === 2}
onClick={() => setTab(MENU_ITEMS[2])}
/>
<Item
icon="check"
text="Integrations"
completed={activeIndex >= 3}
active={activeIndex === 3}
@ -93,4 +86,4 @@ const OnboardingMenu = (props) => {
);
};
export default withRouter(OnboardingMenu);
export default OnboardingMenu;

View file

@ -1,9 +1,9 @@
import React from 'react'
import { withRouter } from 'react-router'
import { Button } from 'antd'
import { OB_TABS, onboarding as onboardingRoute, withSiteId } from 'App/routes'
import { sessions } from 'App/routes';
import { useStore } from 'App/mstore'
import { useParams, useNavigate } from "react-router";
const MENU_ITEMS = [OB_TABS.INSTALLING, OB_TABS.IDENTIFY_USERS, OB_TABS.MANAGE_USERS, OB_TABS.INTEGRATIONS]
const BTN_MSGS = [
@ -13,7 +13,9 @@ const BTN_MSGS = [
'See Recorded Sessions'
]
const OnboardingNavButton = ({ match: { params: { activeTab, siteId } }, history }) => {
const OnboardingNavButton = () => {
const { activeTab, siteId } = useParams();
const navigate = useNavigate();
const { userStore } = useStore();
const activeIndex = MENU_ITEMS.findIndex(i => i === activeTab);
const completed = activeIndex == MENU_ITEMS.length - 1;
@ -21,7 +23,7 @@ const OnboardingNavButton = ({ match: { params: { activeTab, siteId } }, history
const setTab = () => {
if (!completed) {
const tab = MENU_ITEMS[activeIndex+1]
history.push(withSiteId(onboardingRoute(tab), siteId));
navigate(withSiteId(onboardingRoute(tab), siteId));
} else {
onDone()
}
@ -29,7 +31,7 @@ const OnboardingNavButton = ({ match: { params: { activeTab, siteId } }, history
const onDone = () => {
userStore.setOnboarding(true);
history.push(sessions());
navigate(sessions());
}
return (
@ -53,4 +55,4 @@ const OnboardingNavButton = ({ match: { params: { activeTab, siteId } }, history
)
}
export default withRouter(OnboardingNavButton)
export default OnboardingNavButton

View file

@ -1,53 +1,38 @@
import React, { useMemo } from 'react';
import { withRouter, RouteComponentProps } from 'react-router-dom';
import { sessions, withSiteId, onboarding as onboardingRoute } from 'App/routes';
import { observer } from 'mobx-react-lite';
import { useStore } from 'App/mstore';
import { useParams, useNavigate } from "react-router";
export interface WithOnboardingProps {
history: RouteComponentProps['history'];
skip?: () => void;
navTo?: (tab: string) => void;
site?: any;
match: {
params: {
activeTab: string;
siteId: string;
};
};
}
const withOnboarding = <P extends RouteComponentProps>(
Component: React.ComponentType<P & WithOnboardingProps>
const withOnboarding = <P extends Record<string, any>>(
Component: React.ComponentType<P>
) => {
const WithOnboarding: React.FC<P & WithOnboardingProps> = (props) => {
const { siteId } = useParams();
const navigate = useNavigate();
const { projectsStore, userStore } = useStore();
const sites = projectsStore.list;
const {
match: {
params: { siteId },
},
} = props;
const site = useMemo(() => sites.find((s: any) => s.id === siteId), [sites, siteId]);
const skip = () => {
userStore.setOnboarding(true);
props.history.push(withSiteId(sessions(), siteId));
navigate(withSiteId(sessions(), siteId));
};
const navTo = (tab: string) => {
props.history.push(withSiteId(onboardingRoute(tab), siteId));
navigate(withSiteId(onboardingRoute(tab), siteId));
};
return <Component skip={skip} navTo={navTo} {...props} site={site} />;
};
return withRouter(
observer(
WithOnboarding
)
);
return observer(WithOnboarding)
};
export default withOnboarding;

View file

@ -3,27 +3,25 @@ import withPageTitle from 'HOCs/withPageTitle';
import SessionsTabOverview from 'Shared/SessionsTabOverview/SessionsTabOverview';
import FFlagsList from 'Components/FFlags';
import NewFFlag from 'Components/FFlags/NewFFlag';
import { Switch, Route } from 'react-router';
import { sessions, fflags, withSiteId, newFFlag, fflag, fflagRead, bookmarks } from 'App/routes';
import { withRouter, RouteComponentProps, useLocation } from 'react-router-dom';
import { Routes, Route } from 'react-router';
import {
sessions,
fflags,
withSiteId,
newFFlag,
fflag,
fflagRead,
bookmarks,
} from 'App/routes';
import { useLocation, useParams, useNavigate } from 'react-router';
import FlagView from 'Components/FFlags/FlagView/FlagView';
import { observer } from 'mobx-react-lite';
import { useStore } from '@/mstore';
import Bookmarks from 'Shared/SessionsTabOverview/components/Bookmarks/Bookmarks';
// @ts-ignore
interface IProps extends RouteComponentProps {
match: {
params: {
siteId: string;
fflagId?: string;
};
};
}
// TODO should move these routes to the Routes file
function Overview({ match: { params } }: IProps) {
function Overview() {
const { searchStore } = useStore();
const { siteId, fflagId } = params;
const { siteId, fflagId } = useParams();
const location = useLocation();
const tab = location.pathname.split('/')[2];
@ -31,34 +29,50 @@ function Overview({ match: { params } }: IProps) {
searchStore.setActiveTab(tab);
}, [tab]);
return (
<Switch>
<Route exact strict
path={withSiteId(sessions(), siteId)}>
console.log(location.pathname)
const renderContent = () => {
const path = location.pathname;
if (path.startsWith(withSiteId(sessions()), siteId)) {
return (
<div className="mb-5 w-full mx-auto" style={{ maxWidth: '1360px' }}>
<SessionsTabOverview />
</div>
</Route>
<Route exact strict
path={withSiteId(bookmarks(), siteId)}>
);
}
if (path.startsWith(withSiteId(bookmarks()), siteId)) {
return (
<div className="mb-5 w-full mx-auto" style={{ maxWidth: '1360px' }}>
<Bookmarks />
</div>
</Route>
<Route exact strict path={withSiteId(fflags(), siteId)}>
<FFlagsList siteId={siteId} />
</Route>
<Route exact strict path={withSiteId(newFFlag(), siteId)}>
<NewFFlag siteId={siteId} />
</Route>
<Route exact strict path={withSiteId(fflag(), siteId)}>
<NewFFlag siteId={siteId} fflagId={fflagId} />
</Route>
<Route exact strict path={withSiteId(fflagRead(), siteId)}>
<FlagView siteId={siteId} fflagId={fflagId!} />
</Route>
</Switch>
);
);
}
if (path.startsWith(withSiteId(fflags()), siteId)) {
return <FFlagsList siteId={siteId} />;
}
if (path.startsWith(withSiteId(newFFlag()), siteId)) {
return <NewFFlag siteId={siteId} />;
}
if (path.match(new RegExp(`^${withSiteId(fflag(), siteId).replace(':fflagId', '\\d+')}$`))) {
return <NewFFlag siteId={siteId} fflagId={fflagId} />;
}
if (path.match(new RegExp(`^${withSiteId(fflagRead(), siteId).replace(':fflagId', '\\d+')}$`))) {
return <FlagView siteId={siteId} fflagId={fflagId!} />;
}
return (
<div className="mb-5 w-full mx-auto" style={{ maxWidth: '1360px' }}>
<SessionsTabOverview />
</div>
);
};
return renderContent();
}
export default withPageTitle('Sessions - OpenReplay')(withRouter(observer(Overview)));
export default withPageTitle('Sessions - OpenReplay')(observer(Overview));

View file

@ -1,7 +1,7 @@
import { ArrowRightOutlined } from '@ant-design/icons';
import { Button, Card, Radio } from 'antd';
import React from 'react';
import { useHistory } from 'react-router-dom';
import { useNavigate } from 'react-router';
import * as routes from 'App/routes'
import { SPOT_ONBOARDING } from "App/constants/storageKeys";
import { useStore } from 'App/mstore';
@ -27,24 +27,24 @@ function ScopeForm() {
const downgradeScope = userStore.downgradeScope
const scopeState = userStore.scopeState
const [scope, setScope] = React.useState(getDefaultSetup);
const navigate = useNavigate()
React.useEffect(() => {
if (scopeState !== 0) {
if (scopeState === 2) {
history.replace(routes.onboarding())
navigate(routes.onboarding(), { replace: true })
} else {
history.replace(routes.spotsList())
navigate(routes.spotsList(), { replace: true })
}
}
}, [scopeState])
const history = useHistory();
const onContinue = () => {
if (scope === Scope.FULL) {
void upgradeScope();
history.replace(routes.onboarding())
navigate(routes.onboarding(), { replace: true })
} else {
void downgradeScope();
history.replace(routes.spotsList())
navigate(routes.spotsList(), { replace: true })
}
};
return (

View file

@ -4,7 +4,7 @@ import { PlayButton, PlayingState } from '@/player-ui';
import { PlayerContext } from 'Components/Session/playerContext';
import { observer } from 'mobx-react-lite';
import { Button } from 'antd';
import { useHistory } from 'react-router-dom';
import { useNavigate } from 'react-router';
import { CirclePlay } from 'lucide-react';
import { withSiteId } from '@/routes';
import * as routes from '@/routes';
@ -20,7 +20,7 @@ function ClipPlayerControls({
}) {
const { projectsStore } = useStore();
const { player, store } = React.useContext(PlayerContext);
const history = useHistory();
const navigate = useNavigate();
const siteId = projectsStore.siteId;
const { playing, completed } = store.get();
@ -37,7 +37,7 @@ function ClipPlayerControls({
const showFullSession = () => {
const path = withSiteId(routes.session(session.sessionId), siteId);
history.push(path + '?jumpto=' + Math.round(range[0]));
navigate(path + '?jumpto=' + Math.round(range[0]));
};
return (

View file

@ -3,7 +3,7 @@ import cn from 'classnames';
import { Icon } from 'UI';
import { useStore } from 'App/mstore';
import { observer } from 'mobx-react-lite';
import { useHistory } from 'react-router-dom';
import { useNavigate } from 'react-router';
import { multiview, liveSession, withSiteId } from 'App/routes';
import { PlayerContext, ILivePlayerContext } from 'App/components/Session/playerContext';
@ -44,7 +44,7 @@ const CurrentTab = React.memo(() => (
));
function AssistTabs({ session }: { session: Record<string, any> }) {
const history = useHistory();
const navigate = useNavigate();
const { store } = React.useContext(PlayerContext) as unknown as ILivePlayerContext
const { recordingState, calling, remoteControl } = store.get()
const isDisabled = recordingState !== 0 || calling !== 0 || remoteControl !== 0
@ -63,12 +63,12 @@ function AssistTabs({ session }: { session: Record<string, any> }) {
const openGrid = () => {
if (isDisabled) return;
const sessionIdQuery = encodeURIComponent(assistMultiviewStore.sessions.map((s) => s.sessionId).join(','));
return history.push(withSiteId(multiview(sessionIdQuery), siteId));
return navigate(withSiteId(multiview(sessionIdQuery), siteId));
};
const openLiveSession = (sessionId: string) => {
if (isDisabled) return;
assistMultiviewStore.setActiveSession(sessionId);
history.push(withSiteId(liveSession(sessionId), siteId));
navigate(withSiteId(liveSession(sessionId), siteId));
};
return (

View file

@ -1,5 +1,5 @@
import React from 'react';
import { useHistory } from 'react-router-dom';
import { useNavigate } from 'react-router';
import {
withSiteId,
multiview,
@ -24,7 +24,7 @@ function LivePlayerBlockHeader({
const session = sessionStore.current;
const closedLive = sessionStore.fetchFailed || (isAssist && !session.live);
const siteId = projectsStore.siteId;
const history = useHistory();
const navigate = useNavigate()
const { width, height } = store.get();
const metaList = customFieldStore.list.map((i: any) => i.key)
@ -35,7 +35,7 @@ function LivePlayerBlockHeader({
}, []);
const backHandler = () => {
history.goBack();
navigate(-1)
};
const { userId, metadata, isCallActive, agentIds } = session;
@ -48,7 +48,7 @@ function LivePlayerBlockHeader({
const openGrid = () => {
const sessionIdQuery = encodeURIComponent(assistMultiviewStore.sessions.map((s) => s?.sessionId).join(','));
return history.push(withSiteId(multiview(sessionIdQuery), siteId));
return navigate(withSiteId(multiview(sessionIdQuery), siteId));
};
return (

View file

@ -1,7 +1,7 @@
import cn from 'classnames';
import { observer } from 'mobx-react-lite';
import React from 'react';
import { useHistory } from 'react-router';
import { useNavigate } from 'react-router';
import { MobilePlayerContext } from 'App/components/Session/playerContext';
import { FullScreenButton, PlayButton, PlayingState } from 'App/player-ui';
@ -28,7 +28,6 @@ import {
import { useStore } from 'App/mstore';
import { session as sessionRoute, withSiteId } from 'App/routes';
import { SummaryButton } from 'Components/Session_/Player/Controls/Controls';
import { MobEventsList, WebEventsList } from "../../../Session_/Player/Controls/EventsList";
import useShortcuts from '../ReplayPlayer/useShortcuts';
export const SKIP_INTERVALS = {
@ -46,7 +45,7 @@ function Controls(props: any) {
const permissions = userStore.account.permissions || [];
const disableDevtools = userStore.isEnterprise && !(permissions.includes('DEV_TOOLS') || permissions.includes('SERVICE_DEV_TOOLS'));
const { player, store } = React.useContext(MobilePlayerContext);
const history = useHistory();
const navigate = useNavigate()
const { playing, completed, skip, speed, messagesLoading } = store.get();
const { uiPlayerStore, projectsStore } = useStore();
const fullscreen = uiPlayerStore.fullscreen;
@ -68,11 +67,11 @@ function Controls(props: any) {
const sessionTz = session?.timezone;
const nextHandler = () => {
history.push(withSiteId(sessionRoute(nextSessionId), siteId));
navigate(withSiteId(sessionRoute(nextSessionId), siteId));
};
const prevHandler = () => {
history.push(withSiteId(sessionRoute(previousSessionId), siteId));
navigate(withSiteId(sessionRoute(previousSessionId), siteId));
};
useShortcuts({

View file

@ -1,5 +1,5 @@
import React from 'react';
import { useHistory } from 'react-router-dom';
import { useNavigate } from 'react-router';
import { sessions as sessionsRoute, withSiteId } from 'App/routes';
import { BackLink } from 'UI';
import cn from 'classnames';
@ -30,7 +30,7 @@ function PlayerBlockHeader(props: Props) {
const { customFieldStore, projectsStore, sessionStore } = useStore();
const session = sessionStore.current;
const siteId = projectsStore.siteId!;
const history = useHistory();
const navigate = useNavigate();
const {
fullscreen,
setActiveTab,
@ -46,7 +46,7 @@ function PlayerBlockHeader(props: Props) {
}, []);
const backHandler = () => {
history.push(withSiteId(SESSIONS_ROUTE, siteId));
navigate(withSiteId(SESSIONS_ROUTE, siteId));
};
const { metadata } = session;

View file

@ -1,6 +1,5 @@
import { useStore } from "App/mstore";
import React from 'react';
import { withRouter } from 'react-router-dom';
import {
sessions as sessionsRoute,
liveSession as liveSessionRoute,
@ -15,6 +14,7 @@ import { PlayerContext } from 'App/components/Session/playerContext';
import { observer } from 'mobx-react-lite';
import stl from './playerBlockHeader.module.css';
import { IFRAME } from 'App/constants/storageKeys';
import { useNavigate } from "react-router";
const SESSIONS_ROUTE = sessionsRoute();
@ -28,13 +28,12 @@ function PlayerBlockHeader(props: any) {
const playerState = store?.get?.() || { width: 0, height: 0, showEvents: false }
const { width = 0, height = 0, showEvents = false } = playerState
const metaList = customFieldStore.list.map((i: any) => i.key)
const navigate = useNavigate();
const {
fullscreen,
closedLive = false,
setActiveTab,
activeTab,
history,
} = props;
React.useEffect(() => {
@ -46,12 +45,12 @@ function PlayerBlockHeader(props: any) {
const backHandler = () => {
if (
sessionPath.pathname === history.location.pathname ||
sessionPath.pathname === location.pathname ||
sessionPath.pathname.includes('/session/') || sessionPath.pathname.includes('/assist/')
) {
history.push(withSiteId(SESSIONS_ROUTE, siteId));
navigate(withSiteId(SESSIONS_ROUTE, siteId));
} else {
history.push(
navigate(
sessionPath ? sessionPath.pathname + sessionPath.search : withSiteId(SESSIONS_ROUTE, siteId)
);
}
@ -127,4 +126,4 @@ function PlayerBlockHeader(props: any) {
const PlayerHeaderCont = observer(PlayerBlockHeader);
export default withRouter(PlayerHeaderCont);
export default PlayerHeaderCont;

View file

@ -2,7 +2,7 @@ import React from 'react';
import { client as settingsPath, CLIENT_TABS } from 'App/routes';
import { Icon } from 'UI';
import { LoadingOutlined } from '@ant-design/icons';
import { useHistory } from 'react-router-dom';
import { useNavigate } from 'react-router';
import { Button } from 'antd';
export function LoadingFetch({ provider }: { provider: string }) {
@ -25,7 +25,7 @@ export function FailedFetch({
provider: string;
onRetry: () => void;
}) {
const history = useHistory();
const navigate = useNavigate();
const intPath = settingsPath(CLIENT_TABS.INTEGRATIONS);
return (
<div
@ -45,7 +45,7 @@ export function FailedFetch({
Retry
</Button>
<Button type='text' size='small' onClick={() => history.push(intPath)}>
<Button type='text' size='small' onClick={() => navigate(intPath)}>
Check Configuration
</Button>
</div>

View file

@ -1,6 +1,6 @@
import React from 'react';
import { Button, Checkbox, Input } from 'antd';
import { useHistory } from 'react-router-dom';
import { useNavigate } from 'react-router';
import { withSiteId, sessions } from 'App/routes';
import { useStore } from 'App/mstore';
@ -14,7 +14,7 @@ interface Props {
}
function SaveModal({ onSave, hideModal }: Props) {
const history = useHistory();
const navigate = useNavigate();
const { projectsStore, searchStore } = useStore();
const [name, setName] = React.useState('');
const [ignoreClRage, setIgnoreClRage] = React.useState(false);
@ -32,7 +32,7 @@ function SaveModal({ onSave, hideModal }: Props) {
'tag',
tagId.toString(),
)
history.push(
navigate(
withSiteId(
sessions(),
siteId

View file

@ -2,7 +2,7 @@ import React from 'react';
import { useStore } from 'App/mstore';
import { BackLink } from 'UI';
import { observer } from 'mobx-react-lite';
import { useHistory, useParams } from 'react-router-dom';
import { useNavigate, useParams } from 'react-router';
import { liveSession, assist, withSiteId, multiview } from 'App/routes';
import AssistSessionsModal from 'App/components/Session_/Player/Controls/AssistSessionsModal';
import { useModal } from 'App/components/Modal';
@ -19,14 +19,14 @@ function Multiview({
const { showModal, hideModal } = useModal();
const { assistMultiviewStore, projectsStore, searchStoreLive, sessionStore } = useStore();
const siteId = projectsStore.siteId!;
const history = useHistory();
const navigate = useNavigate()
// @ts-ignore
const { sessionsquery } = useParams();
const total = sessionStore.totalLiveSessions;
const onSessionsChange = (sessions: Array<Record<string, any> | undefined>) => {
const sessionIdQuery = encodeURIComponent(sessions.map((s) => s && s.sessionId).join(','));
return history.replace(withSiteId(multiview(sessionIdQuery), siteId));
return navigate(withSiteId(multiview(sessionIdQuery), siteId), { replace: true });
};
React.useEffect(() => {
@ -46,12 +46,12 @@ function Multiview({
const openLiveSession = (e: React.MouseEvent, sessionId: string) => {
e.stopPropagation();
assistMultiviewStore.setActiveSession(sessionId);
history.push(withSiteId(liveSession(sessionId) + '?multi=true', siteId));
navigate(withSiteId(liveSession(sessionId) + '?multi=true', siteId));
};
const returnToList = () => {
assistMultiviewStore.reset();
history.push(withSiteId(assist(), siteId));
navigate(withSiteId(assist(), siteId));
};
const openListModal = () => {

View file

@ -3,7 +3,7 @@ import cn from 'classnames';
import { Icon } from 'UI';
import { useStore } from 'App/mstore';
import { observer } from 'mobx-react-lite';
import { useHistory } from 'react-router-dom';
import { useNavigate } from 'react-router';
import { multiview, liveSession, withSiteId } from 'App/routes';
interface ITab {
@ -42,7 +42,7 @@ const CurrentTab = React.memo(() => (
));
function AssistTabs({ session }: { session: Record<string, any> }) {
const history = useHistory();
const navigate = useNavigate()
const { assistMultiviewStore, projectsStore } = useStore();
const siteId = projectsStore.siteId!;
@ -56,11 +56,11 @@ function AssistTabs({ session }: { session: Record<string, any> }) {
const openGrid = () => {
const sessionIdQuery = encodeURIComponent(assistMultiviewStore.sessions.map((s) => s.sessionId).join(','));
return history.push(withSiteId(multiview(sessionIdQuery), siteId));
return navigate(withSiteId(multiview(sessionIdQuery), siteId));
};
const openLiveSession = (sessionId: string) => {
assistMultiviewStore.setActiveSession(sessionId);
history.push(withSiteId(liveSession(sessionId), siteId));
navigate(withSiteId(liveSession(sessionId), siteId));
};
return (

View file

@ -3,7 +3,7 @@ import { Switch } from 'antd';
import cn from 'classnames';
import { observer } from 'mobx-react-lite';
import React from 'react';
import { useHistory } from 'react-router-dom';
import { useNavigate } from 'react-router';
import { PlayerContext } from 'App/components/Session/playerContext';
import { useStore } from 'App/mstore';
import { FullScreenButton, PlayButton, PlayingState } from 'App/player-ui';
@ -34,7 +34,6 @@ import { Icon } from 'UI';
import LogsButton from 'App/components/Session/Player/SharedComponents/BackendLogs/LogsButton';
import ControlButton from './ControlButton';
import { WebEventsList } from "./EventsList";
import Timeline from './Timeline';
import PlayerControls from './components/PlayerControls';
import styles from './controls.module.css';
@ -92,7 +91,7 @@ function Controls({ setActiveTab }: any) {
const changeSkipInterval = uiPlayerStore.changeSkipInterval;
const skipInterval = uiPlayerStore.skipInterval;
const showStorageRedux = !uiPlayerStore.hiddenHints.storage;
const history = useHistory();
const navigate = useNavigate()
const siteId = projectsStore.siteId;
const {
playing,
@ -113,11 +112,11 @@ function Controls({ setActiveTab }: any) {
const sessionTz = session?.timezone;
const nextHandler = () => {
history.push(withSiteId(sessionRoute(nextSessionId), siteId));
navigate(withSiteId(sessionRoute(nextSessionId), siteId));
};
const prevHandler = () => {
history.push(withSiteId(sessionRoute(previousSessionId), siteId));
navigate(withSiteId(sessionRoute(previousSessionId), siteId));
};
useShortcuts({

View file

@ -1,7 +1,7 @@
import React, { useEffect, useState } from 'react';
import cn from 'classnames';
import { observer } from 'mobx-react-lite';
import { withRouter } from 'react-router-dom';
import { useNavigate } from "react-router";
import { Link } from 'UI';
import { Button } from 'antd'
import { session as sessionRoute, withSiteId } from 'App/routes';
@ -10,7 +10,8 @@ import clsOv from './overlay.module.css';
import AutoplayToggle from 'Shared/AutoplayToggle';
import { useStore } from 'App/mstore';
function AutoplayTimer({ history }: any) {
function AutoplayTimer() {
const navigate = useNavigate();
let timer: NodeJS.Timer;
const [cancelled, setCancelled] = useState(false);
const [counter, setCounter] = useState(5);
@ -25,8 +26,8 @@ function AutoplayTimer({ history }: any) {
}
if (counter === 0) {
const siteId = projectsStore.getSiteId().siteId;
history.push(withSiteId(sessionRoute(nextId), siteId));
const siteId = projectsStore.activeSiteId;
navigate(withSiteId(sessionRoute(nextId), siteId));
}
return () => clearTimeout(timer);
@ -60,14 +61,10 @@ function AutoplayTimer({ history }: any) {
</Link>
</div>
</div>
{/* <div className="mt-2 flex items-center color-gray-dark">
Turn on/off auto-replay in <Icon name="ellipsis-v" className="mx-1" /> More options
</div> */}
</div>
</div>
);
}
export default withRouter(
observer(AutoplayTimer)
);
export default observer(AutoplayTimer)

View file

@ -1,16 +1,16 @@
import React, { useEffect } from 'react';
import { withSiteId, session as sessionRoute } from 'App/routes';
import AutoplayToggle from 'Shared/AutoplayToggle/AutoplayToggle';
import { withRouter, RouteComponentProps } from 'react-router-dom';
import cn from 'classnames';
import { LeftOutlined, RightOutlined } from '@ant-design/icons';
import { Button, Popover } from 'antd';
import { useStore } from 'App/mstore';
import { observer } from 'mobx-react-lite';
import { useParams, useNavigate } from 'react-router';
const PER_PAGE = 10;
interface Props extends RouteComponentProps {
interface Props {
defaultList: any;
currentPage: number;
latestRequestTime: any;
@ -24,12 +24,8 @@ function QueueControls(props: Props) {
const total = sessionStore.total;
const sessionIds = sessionStore.sessionIds ?? [];
const setAutoplayValues = sessionStore.setAutoplayValues;
const {
match: {
// @ts-ignore
params: { sessionId },
},
} = props;
const { sessionId } = useParams();
const navigate = useNavigate();
const currentPage = searchStore.currentPage;
@ -46,13 +42,13 @@ function QueueControls(props: Props) {
}, []);
const nextHandler = () => {
const siteId = projectsStore.getSiteId().siteId!;
props.history.push(withSiteId(sessionRoute(nextId), siteId));
const siteId = projectsStore.activeSiteId!;
navigate(withSiteId(sessionRoute(nextId), siteId));
};
const prevHandler = () => {
const siteId = projectsStore.getSiteId().siteId!;
props.history.push(withSiteId(sessionRoute(previousId), siteId));
const siteId = projectsStore.activeSiteId!;
navigate(withSiteId(sessionRoute(previousId), siteId));
};
return (
@ -108,4 +104,4 @@ function QueueControls(props: Props) {
);
}
export default withRouter(observer(QueueControls));
export default observer(QueueControls);

View file

@ -1,30 +1,19 @@
import React, { useEffect, useState } from 'react';
import { withRouter, RouteComponentProps } from 'react-router-dom';
import { observer } from 'mobx-react-lite';
import { useStore } from 'App/mstore';
import { Icon } from 'UI';
import SignupForm from './SignupForm';
import HealthModal from 'Components/Header/HealthStatus/HealthModal/HealthModal';
import { getHealthRequest } from 'Components/Header/HealthStatus/getHealth';
import withPageTitle from 'HOCs/withPageTitle';
import { login } from 'App/routes';
import Copyright from 'Shared/Copyright';
import { useNavigate } from "react-router";
const LOGIN_ROUTE = login();
const BulletItem: React.FC<{ text: string }> = ({ text }) => (
<div className='flex items-center mb-4'>
<div className='mr-3 h-8 w-8 rounded-full bg-white shadow flex items-center justify-center'>
<Icon name='check' size='26' />
</div>
<div>{text}</div>
</div>
);
const healthStatusCheck_key = '__or__healthStatusCheck_key';
type SignupProps = RouteComponentProps;
const Signup: React.FC<SignupProps> = ({ history }) => {
const Signup = () => {
const navigate = useNavigate();
const { userStore } = useStore();
const authDetails = userStore.authStore.authDetails;
const [healthModalPassed, setHealthModalPassed] = useState<boolean>(localStorage.getItem(healthStatusCheck_key) === 'true');
@ -47,7 +36,7 @@ const Signup: React.FC<SignupProps> = ({ history }) => {
if (!authDetails) return
if (authDetails) {
if (authDetails.tenants) {
history.push(LOGIN_ROUTE);
navigate(LOGIN_ROUTE);
} else {
void getHealth();
}
@ -79,4 +68,4 @@ const Signup: React.FC<SignupProps> = ({ history }) => {
);
};
export default withRouter(withPageTitle('Signup - OpenReplay')(observer(Signup)));
export default withPageTitle('Signup - OpenReplay')(observer(Signup));

View file

@ -1,7 +1,7 @@
import cn from 'classnames';
import { observer } from 'mobx-react-lite';
import React from 'react';
import { useHistory, useParams } from 'react-router-dom';
import { useNavigate, useParams } from 'react-router';
import { useStore } from 'App/mstore';
import {
@ -27,7 +27,7 @@ import spotPlayerStore, { PANELS } from './spotPlayerStore';
function SpotPlayer() {
const defaultHeight = getDefaultPanelHeight();
const history = useHistory();
const navigate = useNavigate()
const [panelHeight, setPanelHeight] = React.useState(defaultHeight);
const { spotStore, userStore } = useStore();
const userEmail = userStore.account.name;
@ -47,7 +47,7 @@ function SpotPlayer() {
if (pubKey) {
spotStore.setAccessKey(pubKey);
} else {
history.push('/');
navigate('/');
}
}
}, [loggedIn]);

View file

@ -20,7 +20,7 @@ import {
import copy from 'copy-to-clipboard';
import { observer } from 'mobx-react-lite';
import React, { useState } from 'react';
import { useHistory } from 'react-router-dom';
import { useNavigate } from 'react-router';
import Tabs from 'App/components/Session/Tabs';
import { useStore } from 'App/mstore';
@ -58,7 +58,7 @@ function SpotPlayerHeader({
const comments = spotStore.currentSpot?.comments ?? [];
const [dropdownOpen, setDropdownOpen] = useState(false);
const history = useHistory();
const navigate = useNavigate()
const onCopy = () => {
copy(window.location.href);
@ -66,7 +66,7 @@ function SpotPlayerHeader({
};
const navigateToSpotsList = () => {
history.push(spotLink);
navigate(spotLink);
};
const items: MenuProps['items'] = [
@ -88,7 +88,7 @@ function SpotPlayerHeader({
await downloadFile(url, `${spotStore.currentSpot!.title}.webm`);
} else if (key === '2') {
spotStore.deleteSpot([spotStore.currentSpot!.spotId]).then(() => {
history.push(spotsList());
navigate(spotsList());
message.success('Spot successfully deleted');
});
}

View file

@ -12,7 +12,7 @@ import { Button, Checkbox, Dropdown, Tooltip } from 'antd';
import copy from 'copy-to-clipboard';
import { Link2 } from 'lucide-react';
import React, { useState } from 'react';
import { useHistory, useParams } from 'react-router-dom';
import { useNavigate, useParams } from 'react-router';
import { toast } from 'react-toastify';
import { TextEllipsis } from "UI";
@ -45,7 +45,7 @@ function SpotListItem({
const [isEdit, setIsEdit] = useState(false);
const [loading, setLoading] = useState(true);
const [tooltipText, setTooltipText] = useState('Copy link to clipboard');
const history = useHistory();
const navigate = useNavigate();
const { siteId } = useParams<{ siteId: string }>();
const menuItems = [
@ -104,7 +104,7 @@ function SpotListItem({
const fullLink = `${window.location.origin}${spotLink}`;
window.open(fullLink, '_blank');
} else {
history.push(withSiteId(spotUrl(spot.spotId.toString()), siteId));
navigate(withSiteId(spotUrl(spot.spotId.toString()), siteId));
}
};

View file

@ -7,14 +7,14 @@ import {
usabilityTestingView,
usabilityTestingEdit,
} from 'App/routes';
import { useParams, useHistory, Prompt } from 'react-router-dom';
import { useNavigate, useParams } from 'react-router';
import Breadcrumb from 'Shared/Breadcrumb';
import { EditOutlined, DeleteOutlined, MoreOutlined } from '@ant-design/icons';
import {Power, Info, ListTodo} from 'lucide-react';
import { useModal } from 'App/components/Modal';
import { observer } from 'mobx-react-lite';
import { useStore } from 'App/mstore';
import { confirm } from 'UI';
import { confirm, NavPrompt } from 'UI';
import StepsModal from './StepsModal';
import SidePanel from './SidePanel';
import usePageTitle from 'App/hooks/usePageTitle';
@ -48,12 +48,12 @@ function TestEdit() {
const [isOverviewEditing, setIsOverviewEditing] = React.useState(false);
const { showModal, hideModal } = useModal();
const history = useHistory();
const navigate = useNavigate()
usePageTitle(`Usability Tests | ${uxtestingStore.instance ? 'Edit' : 'Create'}`);
React.useEffect(() => {
if (uxtestingStore.instanceCreationSiteId && siteId !== uxtestingStore.instanceCreationSiteId) {
history.push(withSiteId(usabilityTesting(), siteId));
navigate(withSiteId(usabilityTesting(), siteId));
}
}, [siteId]);
React.useEffect(() => {
@ -66,7 +66,7 @@ function TestEdit() {
});
} else {
if (!uxtestingStore.instance) {
history.push(withSiteId(usabilityTesting(), siteId));
navigate(withSiteId(usabilityTesting(), siteId));
} else {
setConclusion(uxtestingStore.instance!.conclusionMessage);
setGuidelines(uxtestingStore.instance!.guidelines);
@ -89,16 +89,16 @@ function TestEdit() {
);
} else {
toast.success('The usability test is now live and accessible to participants.');
history.push(withSiteId(usabilityTestingView(testId!.toString()), siteId));
navigate(withSiteId(usabilityTestingView(testId!.toString()), siteId));
}
});
} else {
uxtestingStore.createNewTest(isPreview).then((test) => {
if (isPreview) {
window.open(`${test.startingPath}?oruxt=${test.testId}`, '_blank', 'noopener,noreferrer');
history.replace(withSiteId(usabilityTestingEdit(test.testId), siteId));
navigate(withSiteId(usabilityTestingEdit(test.testId), siteId), { replace: true });
} else {
history.push(withSiteId(usabilityTestingView(test.testId), siteId));
navigate(withSiteId(usabilityTestingView(test.testId), siteId));
}
});
}
@ -128,7 +128,7 @@ function TestEdit() {
})
) {
uxtestingStore.deleteTest(testId).then(() => {
history.push(withSiteId(usabilityTesting(), siteId));
navigate(withSiteId(usabilityTesting(), siteId));
});
}
}
@ -155,7 +155,7 @@ function TestEdit() {
},
]}
/>
<Prompt
<NavPrompt
when={hasChanged}
message={() => {
return 'You have unsaved changes. Are you sure you want to leave?';

View file

@ -4,10 +4,10 @@ import { getPdf2 } from 'Components/AssistStats/pdfGenerator';
import { useModal } from 'Components/Modal';
import LiveTestsModal from 'Components/UsabilityTesting/LiveTestsModal';
import React from 'react';
import { Button, Typography, Select, Space, Popover, Dropdown, Tooltip } from 'antd';
import { Button, Typography, Select, Space, Popover, Dropdown } from 'antd';
import { InfoCircleOutlined } from '@ant-design/icons';
import { withSiteId, usabilityTesting, usabilityTestingEdit } from 'App/routes';
import { useParams, useHistory } from 'react-router-dom';
import { useParams, useNavigate } from 'react-router';
import Breadcrumb from 'Shared/Breadcrumb';
import { observer } from 'mobx-react-lite';
import { useStore } from 'App/mstore';
@ -91,7 +91,7 @@ function TestOverview() {
// @ts-ignore
const { siteId, testId } = useParams();
const { showModal, hideModal } = useModal();
const history = useHistory();
const navigate = useNavigate()
const { uxtestingStore } = useStore();
React.useEffect(() => {
@ -99,7 +99,7 @@ function TestOverview() {
try {
await uxtestingStore.getTest(testId);
} catch {
history.push(withSiteId(usabilityTesting(), siteId));
navigate(withSiteId(usabilityTesting(), siteId));
}
};
@ -375,7 +375,7 @@ const TaskSummary = observer(() => {
const Title = observer(({ testId, siteId }: any) => {
const [truncate, setTruncate] = React.useState(true);
const { uxtestingStore } = useStore();
const history = useHistory();
const navigate = useNavigate()
const handleChange = (value: string) => {
uxtestingStore.updateTestStatus(value);
@ -411,7 +411,7 @@ const Title = observer(({ testId, siteId }: any) => {
})
) {
uxtestingStore.deleteTest(testId).then(() => {
history.push(withSiteId(usabilityTesting(), siteId));
navigate(withSiteId(usabilityTesting(), siteId));
});
}
}
@ -441,7 +441,7 @@ const Title = observer(({ testId, siteId }: any) => {
confirmButton: 'Edit'
})
) {
history.push(withSiteId(usabilityTestingEdit(testId), siteId));
navigate(withSiteId(usabilityTestingEdit(testId), siteId));
}
};

View file

@ -9,7 +9,7 @@ import { ICONS } from 'Shared/AnimatedSVG/AnimatedSVG';
import { Loader, NoContent, Pagination, Link, Icon } from 'UI';
import { checkForRecent, getDateFromMill } from 'App/date';
import { ArrowRightOutlined, PlusOutlined } from '@ant-design/icons';
import { useHistory, useParams } from 'react-router-dom';
import { useNavigate, useParams } from 'react-router';
import { withSiteId, usabilityTestingEdit, usabilityTestingView } from 'App/routes';
import { debounce } from 'App/utils';
import withPageTitle from 'HOCs/withPageTitle';
@ -45,7 +45,7 @@ function TestsTable() {
// @ts-ignore
const { siteId } = useParams();
const history = useHistory();
const navigate = useNavigate()
const onClose = (confirmed: boolean) => {
if (confirmed) {
@ -65,7 +65,7 @@ function TestsTable() {
};
const redirect = (path: string) => {
history.push(withSiteId(usabilityTestingEdit(path), siteId));
navigate(withSiteId(usabilityTestingEdit(path), siteId));
};
return (
@ -197,10 +197,10 @@ const statusMap = {
function Row({ test, siteId }: { test: UxTListEntry; siteId: string }) {
const link = usabilityTestingView(test.testId.toString());
const editLink = usabilityTestingEdit(test.testId.toString());
const history = useHistory();
const navigate = useNavigate()
const redirect = () => {
history.push(withSiteId(test.status === 'preview' ? editLink : link, siteId));
navigate(withSiteId(test.status === 'preview' ? editLink : link, siteId));
};
return (
<div

View file

@ -1,75 +1,77 @@
import React from 'react';
import { withRouter } from 'react-router-dom';
import { useLocation, useNavigate } from 'react-router';
import { removeQueryParams, addQueryParams, setQueryParams, parseQuery } from 'App/routes';
/* eslint-disable react/sort-comp */
const withLocationHandlers = (propNames) => (BaseComponent) => {
@withRouter
class WrapperClass extends React.Component {
getQuery = (names) => parseQuery(this.props.location, names);
getParam = (name) => parseQuery(this.props.location)[name];
addQuery = (params) => {
const { location, history } = this.props;
history.push(addQueryParams(location, params));
};
removeQuery = (names = [], replace = false) => {
const { location, history } = this.props;
const WrapperComponent = (props) => {
const location = useLocation();
const navigate = useNavigate();
const getQuery = (names) => parseQuery(location, names);
const getParam = (name) => parseQuery(location)[name];
const addQuery = (params) => {
navigate(addQueryParams(location, params));
};
const removeQuery = (names = [], replace = false) => {
const namesArray = Array.isArray(names) ? names : [names];
/* to avoid update stack overflow */
const actualNames = Object.keys(this.getQuery(namesArray));
const actualNames = Object.keys(getQuery(namesArray));
if (actualNames.length > 0) {
history[replace ? 'replace' : 'push'](removeQueryParams(location, actualNames));
const path = removeQueryParams(location, actualNames);
navigate(path, { replace });
}
};
setQuery = (params, replace = false) => {
const { location, history } = this.props;
history[replace ? 'replace' : 'push'](setQueryParams(location, params));
};
query = {
all: this.getQuery,
get: this.getParam,
add: this.addQuery,
remove: this.removeQuery,
set: this.setQuery, // TODO: use namespaces
const setQuery = (params, replace = false) => {
navigate(setQueryParams(location, params), { replace });
};
getHash = () => this.props.location.hash.substring(1);
setHash = (hash) => {
const { location, history } = this.props;
history.push({ ...location, hash: `#${hash}` });
};
removeHash = () => {
const { location, history } = this.props;
history.push({ ...location, hash: '' });
};
hash = {
get: this.getHash,
set: this.setHash,
remove: this.removeHash,
const query = {
all: getQuery,
get: getParam,
add: addQuery,
remove: removeQuery,
set: setQuery, // TODO: use namespaces
};
getQueryProps() {
if (Array.isArray(propNames)) return this.getQuery(propNames);
const getHash = () => location.hash.substring(1);
const setHash = (hash) => {
navigate({ ...location, hash: `#${hash}` });
};
const removeHash = () => {
navigate({ ...location, hash: '' });
};
const hash = {
get: getHash,
set: setHash,
remove: removeHash,
};
const getQueryProps = () => {
if (Array.isArray(propNames)) return getQuery(propNames);
if (propNames !== null && typeof propNames === 'object') {
const values = Object.values(propNames);
const query = this.getQuery(values);
const query = getQuery(values);
const queryProps = {};
Object.keys(propNames).map((key) => {
Object.keys(propNames).forEach((key) => {
queryProps[key] = query[propNames[key]];
});
return queryProps;
}
return {};
}
};
render() {
const queryProps = this.getQueryProps();
return <BaseComponent query={this.query} hash={this.hash} {...queryProps} {...this.props} />;
}
}
return WrapperClass;
const queryProps = getQueryProps();
return <BaseComponent query={query} hash={hash} {...queryProps} {...props} />;
};
return WrapperComponent;
};
export default withLocationHandlers;
export default withLocationHandlers;

View file

@ -1,21 +0,0 @@
import React from 'react';
import { withRouter } from 'react-router-dom';
import { withSiteId } from 'App/routes';
import { observer } from 'mobx-react-lite'
import { useStore } from "App/mstore";
export default BaseComponent => withRouter(observer((props) => {
const { history, ...other } = props
const { projectsStore } = useStore();
const siteId = projectsStore.siteId
const push = (location) => {
if (typeof location === 'string') {
history.push(withSiteId(location, siteId));
} else if (typeof location === 'object') {
history.push({ ...location, pathname: withSiteId(location.pathname, siteId) });
}
}
return <BaseComponent {...other} history={{ ...history, push: push }} />
}))

View file

@ -1,13 +1,15 @@
import React, { useEffect, useRef } from 'react';
import { useStore } from "App/mstore";
import { observer } from 'mobx-react-lite'
import { useParams, useNavigate } from 'react-router';
const withSiteIdUpdater = (BaseComponent) => {
const WrapperComponent = (props) => {
const { siteId: urlSiteId } = useParams();
const navigate = useNavigate();
const { projectsStore } = useStore();
const siteId = projectsStore.siteId;
const setSiteId = projectsStore.setSiteId;
const urlSiteId = props.match.params.siteId
const prevSiteIdRef = useRef(siteId);
useEffect(() => {
@ -17,15 +19,15 @@ const withSiteIdUpdater = (BaseComponent) => {
}, []);
useEffect(() => {
const { location: { pathname }, history } = props;
const pathname = location.pathname;
const shouldUrlUpdate = urlSiteId && parseInt(urlSiteId, 10) !== parseInt(siteId, 10);
if (shouldUrlUpdate) {
const path = ['', siteId].concat(pathname.split('/').slice(2)).join('/');
history.push(path);
navigate(path);
}
prevSiteIdRef.current = siteId;
}, [urlSiteId, siteId, props.location.pathname, props.history]);
}, [urlSiteId, siteId, location.pathname]);
const key = siteId;

View file

@ -1,14 +1,14 @@
import React from 'react';
import { Button } from 'antd';
import { useHistory } from 'react-router-dom';
import { useNavigate } from 'react-router';
import { LeftOutlined, ArrowLeftOutlined } from '@ant-design/icons';
function BackButton({ compact }: { compact?: boolean }) {
const history = useHistory();
const navigate = useNavigate()
const siteId = location.pathname.split('/')[1];
const handleBackClick = () => {
history.push(`/${siteId}/dashboard`);
navigate(`/${siteId}/dashboard`);
};
if (compact) {
return (

View file

@ -1,13 +1,13 @@
import React from 'react';
import { useNavigate } from "react-router";
import { Icon } from 'UI';
import cn from 'classnames';
import { Step } from 'App/mstore/types/gettingStarted';
import { useStore } from 'App/mstore';
import { onboarding as onboardingRoute, withSiteId } from 'App/routes';
import { RouteComponentProps, withRouter } from 'react-router';
import { useModal } from 'App/components/Modal';
interface StepListProps extends RouteComponentProps {
interface StepListProps {
title: string;
steps: Step[];
status: 'pending' | 'completed';
@ -61,6 +61,7 @@ const StepItem = React.memo(
);
const StepList = React.memo((props: StepListProps) => {
const navigate = useNavigate()
const { title, steps } = props;
const { hideModal } = useModal();
@ -79,10 +80,9 @@ const StepList = React.memo((props: StepListProps) => {
}
const onClick = (step: any) => {
const { history } = props;
const siteId = projectsStore.getSiteId().siteId!;
hideModal();
history.push(withSiteId(onboardingRoute(step.url), siteId));
navigate(withSiteId(onboardingRoute(step.url), siteId));
};
return (
@ -97,4 +97,4 @@ const StepList = React.memo((props: StepListProps) => {
);
});
export default withRouter(StepList);
export default StepList;

View file

@ -2,12 +2,12 @@ import React from 'react'
import { Icon } from 'UI'
import { Button } from 'antd'
import { CLIENT_TABS, client as clientRoute } from 'App/routes';
import { withRouter } from 'react-router-dom';
function IntegrateSlackTeamsButton({ history }) {
import { useNavigate } from "react-router";
function IntegrateSlackTeamsButton() {
const navigate = useNavigate();
const gotoPreferencesIntegrations = () => {
history.push(clientRoute(CLIENT_TABS.INTEGRATIONS));
navigate(clientRoute(CLIENT_TABS.INTEGRATIONS));
}
return (
@ -26,4 +26,4 @@ function IntegrateSlackTeamsButton({ history }) {
)
}
export default withRouter(IntegrateSlackTeamsButton)
export default IntegrateSlackTeamsButton

View file

@ -3,17 +3,16 @@ import { Alert, Space, Button } from 'antd';
import { observer } from 'mobx-react-lite'
import { useStore } from "App/mstore";
import { onboarding as onboardingRoute } from 'App/routes';
import { withRouter } from 'react-router-dom';
import * as routes from '../../../routes';
import { SquareArrowOutUpRight } from 'lucide-react';
import { useHistory } from 'react-router';
import { useNavigate } from 'react-router';
const withSiteId = routes.withSiteId;
const NoSessionsMessage = () => {
const { projectsStore } = useStore();
const siteId = projectsStore.siteId;
const history = useHistory();
const navigate = useNavigate();
const activeSite = projectsStore.active;
const showNoSessions = !!activeSite && !activeSite.recorded;
const onboardingPath = withSiteId(onboardingRoute('installing'), siteId);
@ -41,7 +40,7 @@ const NoSessionsMessage = () => {
<Button
type="default"
size="small"
onClick={() => history.push(onboardingPath)}
onClick={() => navigate(onboardingPath)}
>
Complete Project Setup
</Button>
@ -55,4 +54,4 @@ const NoSessionsMessage = () => {
);
};
export default withRouter(observer(NoSessionsMessage));
export default observer(NoSessionsMessage)

View file

@ -5,11 +5,10 @@ import {
import { Button, Dropdown, MenuProps, Space, Typography } from 'antd';
import cn from 'classnames';
import React from 'react';
import { withRouter } from 'react-router-dom';
import { useLocation } from 'react-router'
import { useStore } from 'App/mstore';
import { observer } from 'mobx-react-lite';
import { hasSiteId, siteChangeAvailable } from 'App/routes';
import NewSiteForm from 'Components/Client/Sites/NewSiteForm';
import { Icon } from 'UI';
import { useModal } from 'Components/ModalContext';
import ProjectForm from 'Components/Client/Projects/ProjectForm';
@ -17,15 +16,15 @@ import Project from '@/mstore/types/project';
const { Text } = Typography;
function ProjectDropdown(props: { location: any }) {
function ProjectDropdown() {
const mstore = useStore();
const location = useLocation();
const { projectsStore, searchStore, searchStoreLive, userStore } = mstore;
const account = userStore.account;
const sites = projectsStore.list;
const siteId = projectsStore.siteId;
const setSiteId = projectsStore.setSiteId;
const initProject = projectsStore.initProject;
const { location } = props;
const isAdmin = account.admin || account.superAdmin;
const activeSite = sites.find((s) => s.id === siteId);
const showCurrent =
@ -139,6 +138,4 @@ function ProjectDropdown(props: { location: any }) {
);
}
export default withRouter(
observer(ProjectDropdown)
);
export default observer(ProjectDropdown)

View file

@ -1,5 +1,5 @@
import React, { useEffect, useState } from 'react';
import { useHistory } from 'react-router';
import { useNavigate } from 'react-router';
import {
liveSession as liveSessionRoute,
@ -31,7 +31,7 @@ interface Props {
function PlayLink(props: Props) {
const { projectsStore } = useStore();
const { isAssist, viewed, sessionId, onClick = null, queryParams } = props;
const history = useHistory();
const navigate = useNavigate()
const defaultIconName = getIconName(viewed);
const [iconName, setIconName] = useState<typeof PLAY_ICON_NAMES[keyof typeof PLAY_ICON_NAMES]>(defaultIconName);
@ -58,7 +58,7 @@ function PlayLink(props: Props) {
} else {
e.preventDefault();
props.beforeOpen();
history.push(replayLink);
navigate(replayLink);
}
}
};

View file

@ -2,7 +2,6 @@ import cn from 'classnames';
import { Duration } from 'luxon';
import { observer } from 'mobx-react-lite';
import React, { useState, useCallback, useMemo } from 'react';
import { RouteComponentProps, useHistory, withRouter } from 'react-router-dom';
import { durationFormatted, formatTimeOrDate } from 'App/date';
import { useStore } from 'App/mstore';
@ -14,7 +13,7 @@ import {
} from 'App/routes';
import { capitalize } from 'App/utils';
import { Avatar, CountryFlag, Icon, Label, TextEllipsis } from 'UI';
import { useLocation } from "react-router";
import Counter from './Counter';
import ErrorBars from './ErrorBars';
import PlayLink from './PlayLink';
@ -78,8 +77,8 @@ const PREFETCH_STATE = {
fetched: 2
};
function SessionItem(props: RouteComponentProps & Props) {
const { location } = useHistory();
function SessionItem(props: Props) {
const location = useLocation();
const { settingsStore, sessionStore } = useStore();
const { timezone, shownTimezone } = settingsStore.sessionSettings;
const [prefetchState, setPrefetched] = useState(PREFETCH_STATE.none);
@ -449,4 +448,4 @@ function SessionItem(props: RouteComponentProps & Props) {
);
}
export default withRouter(observer(SessionItem));
export default observer(SessionItem);

View file

@ -3,7 +3,7 @@ import { FilterKey } from 'Types/filter/filterType';
import SessionItem from 'Shared/SessionItem';
import { NoContent, Loader, Pagination, Icon } from 'UI';
import { Button } from 'antd'
import { useLocation, withRouter } from 'react-router-dom';
import { useLocation } from 'react-router';
import AnimatedSVG, { ICONS } from 'Shared/AnimatedSVG/AnimatedSVG';
import { numberWithCommas } from 'App/utils';
import SessionDateRange from './SessionDateRange';
@ -237,4 +237,4 @@ function SessionList() {
);
}
export default withRouter(observer(SessionList));
export default observer(SessionList);

View file

@ -0,0 +1,46 @@
import { useCallback, useEffect } from 'react';
import { useBlocker } from 'react-router';
function NavigationPrompt({ when, message }: any) {
const blocker = useCallback(
(tx) => {
if (!when) return false;
if (typeof message === 'function') {
const result = message(tx.nextLocation);
if (result === true) return false;
}
return true;
},
[when, message]
);
const { state, proceed, reset, location: nextLocation } = useBlocker(blocker);
useEffect(() => {
if (state === 'blocked') {
let promptMessage = 'Are you sure you want to leave this page?';
if (typeof message === 'function') {
const result = message(nextLocation);
if (typeof result === 'string') {
promptMessage = result;
}
} else if (typeof message === 'string') {
promptMessage = message;
}
const confirmed = window.confirm(promptMessage);
if (confirmed) {
proceed();
} else {
reset();
}
}
}, [state, proceed, reset, nextLocation, message]);
return null;
}
export default NavigationPrompt;

View file

@ -1,6 +1,6 @@
import { observer } from 'mobx-react-lite';
import React from 'react';
import { RouteComponentProps, withRouter } from 'react-router-dom';
import { useNavigate, useLocation } from "react-router";
import { useStore } from 'App/mstore';
import {
@ -16,8 +16,7 @@ import stl from './NoSessionPermission.module.css';
const SESSIONS_ROUTE = sessionsRoute();
const ASSIST_ROUTE = assistRoute();
interface Props extends RouteComponentProps {
history: any;
interface Props {
isLive?: boolean;
}
function NoSessionPermission(props: Props) {
@ -26,19 +25,20 @@ function NoSessionPermission(props: Props) {
const sessionPath = sessionStore.sessionPath;
const isAssist = window.location.pathname.includes('/assist/');
const siteId = projectsStore.siteId!;
const { history } = props;
const navigate = useNavigate();
const location = useLocation();
const backHandler = () => {
if (
sessionPath.pathname === history.location.pathname ||
sessionPath.pathname === location.pathname ||
sessionPath.pathname.includes('/session/') ||
isAssist
) {
history.push(
navigate(
withSiteId(isAssist ? ASSIST_ROUTE : SESSIONS_ROUTE, siteId)
);
} else {
history.push(
navigate(
sessionPath
? sessionPath.pathname + sessionPath.search
: withSiteId(SESSIONS_ROUTE, siteId)
@ -50,7 +50,7 @@ function NoSessionPermission(props: Props) {
<div className={stl.wrapper}>
<Icon name="shield-lock" size="50" className="py-16" />
<div className={stl.title}>Not allowed</div>
{session.isLive ? (
{session.live ? (
<span>
This session is still live, and you dont have the necessary
permissions to access this feature. Please check with your admin.
@ -68,6 +68,4 @@ function NoSessionPermission(props: Props) {
);
}
export default withRouter(
observer(NoSessionPermission)
);
export default observer(NoSessionPermission)

View file

@ -47,4 +47,5 @@ export { default as Message } from './Message';
export { default as Popover } from './Popover';
export { default as Switch } from './Switch';
export { default as Divider } from './Divider';
export { default as CodeBlock } from './CodeBlock'
export { default as CodeBlock } from './CodeBlock'
export { default as NavPrompt } from './NavPrompt';

View file

@ -1,5 +1,5 @@
import { useEffect, useState } from 'react';
import { useHistory } from 'react-router';
import { useNavigate } from 'react-router';
import { JsonUrlConverter } from 'App/utils/search';
import { useStore } from '@/mstore';
import Search from '@/mstore/types/search';
@ -15,7 +15,7 @@ interface Props {
const useSessionSearchQueryHandler = ({ onBeforeLoad, appliedFilter, loading, onLoaded = () => null }: Props) => {
const { searchStore } = useStore();
const [beforeHookLoaded, setBeforeHookLoaded] = useState(!onBeforeLoad);
const history = useHistory();
const navigate = useNavigate()
// Apply filter from the query string when the component mounts
useEffect(() => {
@ -27,7 +27,7 @@ const useSessionSearchQueryHandler = ({ onBeforeLoad, appliedFilter, loading, on
setBeforeHookLoaded(true);
}
const converter = JsonUrlConverter.urlParamsToJson(history.location.search);
const converter = JsonUrlConverter.urlParamsToJson(location.search);
const json = getFilterFromJson(converter.toJSON());
const filter = new Search(json);
@ -57,27 +57,27 @@ const useSessionSearchQueryHandler = ({ onBeforeLoad, appliedFilter, loading, on
};
void applyFilterFromQuery();
}, [loading, searchStore, history.location.search, onBeforeLoad]);
}, [loading, searchStore, location.search, onBeforeLoad]);
// Update the URL whenever the appliedFilter changes
useEffect(() => {
const updateUrlWithFilter = () => {
if (!loading && beforeHookLoaded) {
const query = JsonUrlConverter.jsonToUrlParams(appliedFilter);
history.replace({ search: query });
navigate({ search: query }, { replace: true });
}
};
updateUrlWithFilter();
}, [appliedFilter, loading, beforeHookLoaded, history]);
}, [appliedFilter, loading, beforeHookLoaded]);
// Ensure the URL syncs on remount if already parsed
useEffect(() => {
if (searchStore.urlParsed) {
const query = JsonUrlConverter.jsonToUrlParams(appliedFilter);
history.replace({ search: query });
navigate({ search: query }, { replace: true });
}
}, [appliedFilter, searchStore.urlParsed, history]);
}, [appliedFilter, searchStore.urlParsed]);
return null;
};

View file

@ -1,9 +1,8 @@
import { Divider, Menu, Tag, Typography, Popover, Button } from 'antd';
import cn from 'classnames';
import React from 'react';
import { RouteComponentProps, withRouter } from 'react-router-dom';
import { observer } from 'mobx-react-lite';
import { useLocation, useNavigate } from 'react-router';
import SupportModal from 'App/layout/SupportModal';
import * as routes from 'App/routes';
import {
@ -30,15 +29,15 @@ import AnimatedSVG, { ICONS } from 'Shared/AnimatedSVG/AnimatedSVG';
const { Text } = Typography;
interface Props extends RouteComponentProps {
siteId?: string;
interface Props {
isCollapsed?: boolean;
}
function SideMenu(props: Props) {
const location = useLocation();
const navigate = useNavigate();
const {
location,
isCollapsed
isCollapsed,
} = props;
const isPreferencesActive = location.pathname.includes('/client/');
@ -118,7 +117,7 @@ function SideMenu(props: Props) {
const menuRoutes: any = {
[MENU.EXIT]: () =>
props.history.push(withSiteId(routes.sessions(), siteId)),
navigate(withSiteId(routes.sessions(), siteId)),
[MENU.SESSIONS]: () => withSiteId(routes.sessions(), siteId),
[MENU.BOOKMARKS]: () => withSiteId(routes.bookmarks(), siteId),
[MENU.VAULT]: () => withSiteId(routes.bookmarks(), siteId),
@ -169,7 +168,7 @@ function SideMenu(props: Props) {
};
const pushTo = (path: string) => {
props.history.push(path);
navigate(path);
};
const RenderDivider = (props: { index: number }) => {
@ -324,8 +323,7 @@ function SideMenu(props: Props) {
);
}
export default withRouter(observer(SideMenu));
export default observer(SideMenu);
const SpotMenuItem = ({ isCollapsed }: any) => {
const [isModalVisible, setIsModalVisible] = React.useState(false);

View file

@ -1,7 +1,7 @@
import React from 'react';
import { Modal, Button, List, Divider } from 'antd';
import { CircleDot, Play, TrendingUp, Radio, Sparkles, Plug, ArrowRight } from 'lucide-react';
import { useHistory } from 'react-router-dom';
import { useNavigate } from 'react-router';
import { onboarding } from 'App/routes';
import { useStore } from 'App/mstore';
@ -15,7 +15,7 @@ const SpotToOpenReplayPrompt = ({ isVisible, onCancel }: {
onCancel: () => void;
}) => {
const { userStore } = useStore();
const history = useHistory();
const navigate = useNavigate()
const features = [
{ icon: <CircleDot />, text: 'Spot', noBorder: true },
{ isDivider: true },
@ -28,7 +28,7 @@ const SpotToOpenReplayPrompt = ({ isVisible, onCancel }: {
const onUpgrade = () => {
userStore.upgradeScope().then(() => {
history.push(onboarding());
navigate(onboarding());
onCancel();
})
}

View file

@ -62,8 +62,8 @@
"react-draggable": "^4.4.5",
"react-google-recaptcha": "^2.1.0",
"react-intersection-observer": "^9.13.1",
"react-router": "^5.3.3",
"react-router-dom": "^5.3.3",
"react-router": "^6.30.0",
"react-router-dom": "^6.30.0",
"react-select": "^5.3.2",
"react-svg-map": "^2.2.0",
"react-toastify": "^9.1.1",

View file

@ -1581,7 +1581,7 @@ __metadata:
languageName: node
linkType: hard
"@babel/runtime@npm:^7.1.2, @babel/runtime@npm:^7.10.1, @babel/runtime@npm:^7.10.4, @babel/runtime@npm:^7.11.1, @babel/runtime@npm:^7.11.2, @babel/runtime@npm:^7.12.0, @babel/runtime@npm:^7.12.13, @babel/runtime@npm:^7.12.5, @babel/runtime@npm:^7.16.7, @babel/runtime@npm:^7.18.0, @babel/runtime@npm:^7.18.3, @babel/runtime@npm:^7.20.0, @babel/runtime@npm:^7.20.7, @babel/runtime@npm:^7.21.0, @babel/runtime@npm:^7.22.5, @babel/runtime@npm:^7.23.2, @babel/runtime@npm:^7.23.6, @babel/runtime@npm:^7.23.9, @babel/runtime@npm:^7.24.4, @babel/runtime@npm:^7.24.7, @babel/runtime@npm:^7.24.8, @babel/runtime@npm:^7.25.7, @babel/runtime@npm:^7.26.0, @babel/runtime@npm:^7.5.5, @babel/runtime@npm:^7.8.4, @babel/runtime@npm:^7.8.7, @babel/runtime@npm:^7.9.2":
"@babel/runtime@npm:^7.10.1, @babel/runtime@npm:^7.10.4, @babel/runtime@npm:^7.11.1, @babel/runtime@npm:^7.11.2, @babel/runtime@npm:^7.12.0, @babel/runtime@npm:^7.12.5, @babel/runtime@npm:^7.16.7, @babel/runtime@npm:^7.18.0, @babel/runtime@npm:^7.18.3, @babel/runtime@npm:^7.20.0, @babel/runtime@npm:^7.20.7, @babel/runtime@npm:^7.21.0, @babel/runtime@npm:^7.22.5, @babel/runtime@npm:^7.23.2, @babel/runtime@npm:^7.23.6, @babel/runtime@npm:^7.23.9, @babel/runtime@npm:^7.24.4, @babel/runtime@npm:^7.24.7, @babel/runtime@npm:^7.24.8, @babel/runtime@npm:^7.25.7, @babel/runtime@npm:^7.26.0, @babel/runtime@npm:^7.5.5, @babel/runtime@npm:^7.8.4, @babel/runtime@npm:^7.8.7, @babel/runtime@npm:^7.9.2":
version: 7.26.9
resolution: "@babel/runtime@npm:7.26.9"
dependencies:
@ -2930,6 +2930,13 @@ __metadata:
languageName: node
linkType: hard
"@remix-run/router@npm:1.23.0":
version: 1.23.0
resolution: "@remix-run/router@npm:1.23.0"
checksum: 10c1/c87d2227dc07ec5575cb3349dc388c0abd77a7f04bbdde531b183880c19c9550c3adbeb67a1a2ad677fbf13dd6192e2c42f479d5d99e4f01c7b53f250cec6c00
languageName: node
linkType: hard
"@sentry/browser@npm:^5.21.1":
version: 5.30.0
resolution: "@sentry/browser@npm:5.30.0"
@ -8528,20 +8535,6 @@ __metadata:
languageName: node
linkType: hard
"history@npm:^4.9.0":
version: 4.10.1
resolution: "history@npm:4.10.1"
dependencies:
"@babel/runtime": "npm:^7.1.2"
loose-envify: "npm:^1.2.0"
resolve-pathname: "npm:^3.0.0"
tiny-invariant: "npm:^1.0.2"
tiny-warning: "npm:^1.0.0"
value-equal: "npm:^1.0.1"
checksum: 10c1/52b1a0cc62f6bff70d29325ce3e16078f070e8d51405866ce617c266dbf66a8b3898b5dbd9272514844760e8c3d1e657240d64175ab6b133b8bb100161218b5b
languageName: node
linkType: hard
"hls.js@npm:^1.5.13":
version: 1.5.20
resolution: "hls.js@npm:1.5.20"
@ -8549,7 +8542,7 @@ __metadata:
languageName: node
linkType: hard
"hoist-non-react-statics@npm:^3.1.0, hoist-non-react-statics@npm:^3.3.0, hoist-non-react-statics@npm:^3.3.1, hoist-non-react-statics@npm:^3.3.2":
"hoist-non-react-statics@npm:^3.3.0, hoist-non-react-statics@npm:^3.3.1, hoist-non-react-statics@npm:^3.3.2":
version: 3.3.2
resolution: "hoist-non-react-statics@npm:3.3.2"
dependencies:
@ -9387,13 +9380,6 @@ __metadata:
languageName: node
linkType: hard
"isarray@npm:0.0.1":
version: 0.0.1
resolution: "isarray@npm:0.0.1"
checksum: 10c1/abd2b120df9b6e06385e1d2d109dc4eabac0b950e1a02448cde7416691462d809c32d2acdd28d6c2e2ede3527e6251debc9a56f7c7c8515da4ead1993f6ba514
languageName: node
linkType: hard
"isarray@npm:^2.0.5":
version: 2.0.5
resolution: "isarray@npm:2.0.5"
@ -10563,7 +10549,7 @@ __metadata:
languageName: node
linkType: hard
"loose-envify@npm:^1.0.0, loose-envify@npm:^1.1.0, loose-envify@npm:^1.2.0, loose-envify@npm:^1.3.1, loose-envify@npm:^1.4.0":
"loose-envify@npm:^1.0.0, loose-envify@npm:^1.1.0, loose-envify@npm:^1.3.1, loose-envify@npm:^1.4.0":
version: 1.4.0
resolution: "loose-envify@npm:1.4.0"
dependencies:
@ -11663,8 +11649,8 @@ __metadata:
react-draggable: "npm:^4.4.5"
react-google-recaptcha: "npm:^2.1.0"
react-intersection-observer: "npm:^9.13.1"
react-router: "npm:^5.3.3"
react-router-dom: "npm:^5.3.3"
react-router: "npm:^6.30.0"
react-router-dom: "npm:^6.30.0"
react-select: "npm:^5.3.2"
react-svg-map: "npm:^2.2.0"
react-toastify: "npm:^9.1.1"
@ -11969,15 +11955,6 @@ __metadata:
languageName: node
linkType: hard
"path-to-regexp@npm:^1.7.0":
version: 1.9.0
resolution: "path-to-regexp@npm:1.9.0"
dependencies:
isarray: "npm:0.0.1"
checksum: 10c1/79d0f8f5221b7d1a2c3de08775f7ea158ef7bd978e9ed3c6b0813a89ffcc59edb9eee435913ce73e2aad99384b7101d40d81dfe312cf2f54da53990305108695
languageName: node
linkType: hard
"path-type@npm:^4.0.0":
version: 4.0.0
resolution: "path-type@npm:4.0.0"
@ -13676,7 +13653,7 @@ __metadata:
languageName: node
linkType: hard
"react-is@npm:^16.12.0, react-is@npm:^16.13.1, react-is@npm:^16.6.0, react-is@npm:^16.7.0":
"react-is@npm:^16.12.0, react-is@npm:^16.13.1, react-is@npm:^16.7.0":
version: 16.13.1
resolution: "react-is@npm:16.13.1"
checksum: 10c1/b1d8be84f510ec19f3dc7cebd9790076f708943e333e03a26dfadc225bd36b3ac6bbdc94a19e1cd72f43d366de47e21fa04396aba0e86ae0e50610fb4c7a47c8
@ -13697,39 +13674,27 @@ __metadata:
languageName: node
linkType: hard
"react-router-dom@npm:^5.3.3":
version: 5.3.4
resolution: "react-router-dom@npm:5.3.4"
"react-router-dom@npm:^6.30.0":
version: 6.30.0
resolution: "react-router-dom@npm:6.30.0"
dependencies:
"@babel/runtime": "npm:^7.12.13"
history: "npm:^4.9.0"
loose-envify: "npm:^1.3.1"
prop-types: "npm:^15.6.2"
react-router: "npm:5.3.4"
tiny-invariant: "npm:^1.0.2"
tiny-warning: "npm:^1.0.0"
"@remix-run/router": "npm:1.23.0"
react-router: "npm:6.30.0"
peerDependencies:
react: ">=15"
checksum: 10c1/1a00acf223dc8ffb7eb6c189dcc858858c4df37b51dd92b5d38aca456b9813596094e19fdcdcc8044daad054c5392de051643988c217e3a296d1df803e5106f4
react: ">=16.8"
react-dom: ">=16.8"
checksum: 10c1/00e36b130dcd6fdf7c2867b35ad547b28dfcdbc5b342699baaea785dbfbabd6d3e1d9213c3eb1ffb64e4b418b3a1053882b7ab568a68624f301c2ed88f6d38e5
languageName: node
linkType: hard
"react-router@npm:5.3.4, react-router@npm:^5.3.3":
version: 5.3.4
resolution: "react-router@npm:5.3.4"
"react-router@npm:6.30.0, react-router@npm:^6.30.0":
version: 6.30.0
resolution: "react-router@npm:6.30.0"
dependencies:
"@babel/runtime": "npm:^7.12.13"
history: "npm:^4.9.0"
hoist-non-react-statics: "npm:^3.1.0"
loose-envify: "npm:^1.3.1"
path-to-regexp: "npm:^1.7.0"
prop-types: "npm:^15.6.2"
react-is: "npm:^16.6.0"
tiny-invariant: "npm:^1.0.2"
tiny-warning: "npm:^1.0.0"
"@remix-run/router": "npm:1.23.0"
peerDependencies:
react: ">=15"
checksum: 10c1/b920516e84fc10980a108b1ad368c4ebd3b5541c4de1bb071053c91ccc6410d1a7326aed6da6101d6728ca825ec661e73b87518078502e3a4879f5be924af2d6
react: ">=16.8"
checksum: 10c1/6d8b9dfcfa38b930f49a511d635f02dd66dfed6c120df08c41ebfc661c6c4aa388b59ac63e01ffba55a3f334e199ce2f9f76f1fd50d14fca52e213373c18368f
languageName: node
linkType: hard
@ -14111,13 +14076,6 @@ __metadata:
languageName: node
linkType: hard
"resolve-pathname@npm:^3.0.0":
version: 3.0.0
resolution: "resolve-pathname@npm:3.0.0"
checksum: 10c1/7951bb47cbfc98a2cc0e4b62a099ce4191f01e42557b048cf8bf857092e0719a4d021f9765d770ec8967630656f0a78c4b656908183d09dd680649d20d56851b
languageName: node
linkType: hard
"resolve-pkg-maps@npm:^1.0.0":
version: 1.0.0
resolution: "resolve-pkg-maps@npm:1.0.0"
@ -15607,20 +15565,13 @@ __metadata:
languageName: node
linkType: hard
"tiny-invariant@npm:^1.0.2, tiny-invariant@npm:^1.3.1":
"tiny-invariant@npm:^1.3.1":
version: 1.3.3
resolution: "tiny-invariant@npm:1.3.3"
checksum: 10c1/e9baa182794cfa0499134b3e7a886ab8be2e2cd15e070eedb81e2ae8ff379b8ddba146cb25093242c6768d127a93e7f2ce774c7be9a8035c1b34d02c9a5b0a8c
languageName: node
linkType: hard
"tiny-warning@npm:^1.0.0":
version: 1.0.3
resolution: "tiny-warning@npm:1.0.3"
checksum: 10c1/b559861279695929d2ed06390b7a455186cb796a5fd3fb8efa45de786b45976dcb46d038f1bd9aaa744abe3c3cbc08e6650ce34fabf419bc50e3150106e78751
languageName: node
linkType: hard
"tinyglobby@npm:^0.2.7":
version: 0.2.12
resolution: "tinyglobby@npm:0.2.12"
@ -16259,13 +16210,6 @@ __metadata:
languageName: node
linkType: hard
"value-equal@npm:^1.0.1":
version: 1.0.1
resolution: "value-equal@npm:1.0.1"
checksum: 10c1/90eacdf332d054e39b44e190d72c4975cf3daee09084e16146eb5ae8590683b11a097d552efe9a6bbb3ea56489a06e5ea02c20acba83c1a84e20912a864d7981
languageName: node
linkType: hard
"vary@npm:~1.1.2":
version: 1.1.2
resolution: "vary@npm:1.1.2"