From 9ed207abb1fc0a0278c772261324dc1ecc2ef13b Mon Sep 17 00:00:00 2001 From: Delirium Date: Fri, 13 Sep 2024 18:13:15 +0200 Subject: [PATCH] Dev (#2577) * ui: use enum state for spot ready checker * ui: force worker for hls * ui: fix spot list header behavior, change spot login flow? * ui: bump spot v * ui: spot signup fixes --- frontend/app/PrivateRoutes.tsx | 14 +-- frontend/app/Router.tsx | 65 +++++++------ .../app/components/ScopeForm/ScopeForm.tsx | 96 +++++++++++-------- .../Spots/SpotsList/SpotsListHeader.tsx | 5 +- .../app/components/Spots/SpotsList/index.tsx | 1 + frontend/app/mstore/spotStore.ts | 17 +++- frontend/app/services/spotService.ts | 1 + frontend/app/utils/index.ts | 1 - spot/package.json | 2 +- 9 files changed, 114 insertions(+), 88 deletions(-) diff --git a/frontend/app/PrivateRoutes.tsx b/frontend/app/PrivateRoutes.tsx index 966f73bc5..97f7fac83 100644 --- a/frontend/app/PrivateRoutes.tsx +++ b/frontend/app/PrivateRoutes.tsx @@ -119,6 +119,7 @@ interface Props { function PrivateRoutes(props: Props) { const { onboarding, sites, siteId } = props; const hasRecordings = sites.some(s => s.recorded); + const redirectToSetup = props.scope === 0; const redirectToOnboarding = !onboarding && (localStorage.getItem(GLOBAL_HAS_NO_RECORDINGS) === 'true' || !hasRecordings) && props.scope > 0; const siteIdList: any = sites.map(({ id }) => id).toJS(); @@ -126,6 +127,13 @@ function PrivateRoutes(props: Props) { return ( }> + + {redirectToSetup ? : null} - {props.scope === 1 ? : null} any; - fetchTenants: () => any; setSessionPath: (path: any) => any; fetchSiteList: (siteId?: number) => any; match: { @@ -45,7 +42,7 @@ interface RouterProps }; }; mstore: any; - setJwt: (params: { jwt: string, spotJwt: string | null }) => any; + setJwt: (params: { jwt: string; spotJwt: string | null }) => any; fetchMetadata: (siteId: string) => void; initSite: (site: any) => void; scopeSetup: boolean; @@ -68,15 +65,16 @@ const Router: React.FC = (props) => { logout, } = props; - const params = new URLSearchParams(location.search) + const params = new URLSearchParams(location.search); const spotCb = params.get('spotCallback'); - const spotReqSent = React.useRef(false) + const spotReqSent = React.useRef(false); const [isSpotCb, setIsSpotCb] = React.useState(false); + const [isSignup, setIsSignup] = React.useState(false); const [isIframe, setIsIframe] = React.useState(false); const [isJwt, setIsJwt] = React.useState(false); const handleJwtFromUrl = () => { - const params = new URLSearchParams(location.search) + const params = new URLSearchParams(location.search); const urlJWT = params.get('jwt'); const spotJwt = params.get('spotJwt'); if (spotJwt) { @@ -92,6 +90,7 @@ const Router: React.FC = (props) => { return; } else { spotReqSent.current = true; + setIsSpotCb(false); } handleSpotJWT(jwt); }; @@ -107,13 +106,17 @@ const Router: React.FC = (props) => { const handleUserLogin = async () => { if (isSpotCb) { - localStorage.setItem(SPOT_ONBOARDING, 'true') + localStorage.setItem(SPOT_ONBOARDING, 'true'); } await fetchUserInfo(); const siteIdFromPath = parseInt(location.pathname.split('/')[1]); await fetchSiteList(siteIdFromPath); props.mstore.initClient(); + if (localSpotJwt && !isTokenExpired(localSpotJwt)) { + handleSpotLogin(localSpotJwt); + } + const destinationPath = localStorage.getItem(GLOBAL_DESTINATION_PATH); if ( destinationPath && @@ -144,7 +147,10 @@ const Router: React.FC = (props) => { if (spotCb) { setIsSpotCb(true); } - }, [spotCb]) + if (location.pathname.includes('signup')) { + setIsSignup(true); + } + }, [spotCb]); useEffect(() => { handleDestinationPath(); @@ -159,22 +165,14 @@ const Router: React.FC = (props) => { }, [isLoggedIn]); useEffect(() => { - if (scopeSetup) { - history.push(routes.scopeSetup()) - } - }, [scopeSetup]) - - useEffect(() => { - if (isLoggedIn && (location.pathname.includes('login') || isSpotCb)) { - if (localSpotJwt) { - if (!isTokenExpired(localSpotJwt)) { - handleSpotLogin(localSpotJwt); - } else { - logout(); - } + if (isLoggedIn && isSpotCb && !isSignup) { + if (localSpotJwt && !isTokenExpired(localSpotJwt)) { + handleSpotLogin(localSpotJwt); + } else { + logout(); } } - }, [isSpotCb, location, isLoggedIn, localSpotJwt]) + }, [isSpotCb, isLoggedIn, localSpotJwt, isSignup]); useEffect(() => { if (siteId && siteId !== lastFetchedSiteIdRef.current) { @@ -204,8 +202,7 @@ const Router: React.FC = (props) => { location.pathname.includes('multiview') || location.pathname.includes('/view-spot/') || location.pathname.includes('/spots/') || - location.pathname.includes('/scope-setup') - + location.pathname.includes('/scope-setup'); if (isIframe) { return ( @@ -238,8 +235,11 @@ const mapStateToProps = (state: Map) => { 'loading', ]); const sitesLoading = state.getIn(['site', 'fetchListRequest', 'loading']); - const scopeSetup = getScope(state) === 0 - const loading = Boolean(userInfoLoading) || Boolean(sitesLoading) || (!scopeSetup && !siteId); + const scopeSetup = getScope(state) === 0; + const loading = + Boolean(userInfoLoading) || + Boolean(sitesLoading) || + (!scopeSetup && !siteId); return { siteId, changePassword, @@ -262,7 +262,6 @@ const mapStateToProps = (state: Map) => { const mapDispatchToProps = { fetchUserInfo, - fetchTenants, setSessionPath, fetchSiteList, setJwt, diff --git a/frontend/app/components/ScopeForm/ScopeForm.tsx b/frontend/app/components/ScopeForm/ScopeForm.tsx index 6e762ea94..d87edf752 100644 --- a/frontend/app/components/ScopeForm/ScopeForm.tsx +++ b/frontend/app/components/ScopeForm/ScopeForm.tsx @@ -2,7 +2,7 @@ import { ArrowRightOutlined } from '@ant-design/icons'; import { Button, Card, Radio } from 'antd'; import React from 'react'; import { connect } from 'react-redux'; -import { upgradeScope, downgradeScope } from "App/duck/user"; +import { upgradeScope, downgradeScope, getScope } from 'App/duck/user'; import { useHistory } from 'react-router-dom'; import * as routes from 'App/routes' import { SPOT_ONBOARDING } from "../../constants/storageKeys"; @@ -15,8 +15,18 @@ const Scope = { function ScopeForm({ upgradeScope, downgradeScope, + scopeState, }: any) { const [scope, setScope] = React.useState(Scope.FULL); + React.useEffect(() => { + if (scopeState !== 0) { + if (scopeState === 2) { + history.replace(routes.onboarding()) + } else { + history.replace(routes.spotsList()) + } + } + }, [scopeState]) React.useEffect(() => { const isSpotSetup = localStorage.getItem(SPOT_ONBOARDING) if (isSpotSetup) { @@ -36,50 +46,52 @@ function ScopeForm({ }; return (
- -
- How will you primarily use OpenReplay?{' '} -
-
-
- You will have access to all OpenReplay features regardless of your - choice. -
-
- Your preference will simply help us tailor your onboarding experience. -
-
- setScope(e.target.value)} - className={'flex flex-col gap-2 mt-4 '} + - - Session Replay & Debugging, Customer Support and more - - Report bugs via Spot - - -
- -
-
+ + Session Replay & Debugging, Customer Support and more + + Report bugs via Spot + + +
+ +
+
); } -export default connect(null, { upgradeScope, downgradeScope })(ScopeForm); +export default connect((state) => ({ + scopeState: getScope(state), +}), { upgradeScope, downgradeScope })(ScopeForm); diff --git a/frontend/app/components/Spots/SpotsList/SpotsListHeader.tsx b/frontend/app/components/Spots/SpotsList/SpotsListHeader.tsx index f22ce9242..2ce776eef 100644 --- a/frontend/app/components/Spots/SpotsList/SpotsListHeader.tsx +++ b/frontend/app/components/Spots/SpotsList/SpotsListHeader.tsx @@ -10,7 +10,7 @@ const SpotsListHeader = observer( onDelete, selectedCount, onClearSelection, - isEmpty, + tenantHasSpots, onRefresh, }: { onDelete: () => void; @@ -18,6 +18,7 @@ const SpotsListHeader = observer( onClearSelection: () => void; onRefresh: () => void; isEmpty?: boolean; + tenantHasSpots: boolean; }) => { const { spotStore } = useStore(); @@ -52,7 +53,7 @@ const SpotsListHeader = observer( - {isEmpty ? null : ( + {tenantHasSpots ? null : (
{selectedCount > 0 && ( diff --git a/frontend/app/components/Spots/SpotsList/index.tsx b/frontend/app/components/Spots/SpotsList/index.tsx index 107e7e235..b5b385098 100644 --- a/frontend/app/components/Spots/SpotsList/index.tsx +++ b/frontend/app/components/Spots/SpotsList/index.tsx @@ -89,6 +89,7 @@ function SpotsList() { selectedCount={selectedSpots.length} onClearSelection={clearSelection} isEmpty={isEmpty} + tenantHasSpots={spotStore.tenantHasSpots} />
diff --git a/frontend/app/mstore/spotStore.ts b/frontend/app/mstore/spotStore.ts index 1442ed2e8..71b4571b8 100644 --- a/frontend/app/mstore/spotStore.ts +++ b/frontend/app/mstore/spotStore.ts @@ -1,10 +1,15 @@ import { makeAutoObservable } from 'mobx'; + + import { spotService } from 'App/services'; import { UpdateSpotRequest } from 'App/services/spotService'; + + import { Spot } from './types/spot'; + export default class SpotStore { isLoading: boolean = false; spots: Spot[] = []; @@ -18,6 +23,7 @@ export default class SpotStore { pubKey: { value: string; expiration: number } | null = null; readonly order = 'desc'; accessError = false; + tenantHasSpots = false; constructor() { makeAutoObservable(this); @@ -81,13 +87,18 @@ export default class SpotStore { limit: this.limit, } as const; - const response = await this.withLoader(() => + const { spots, tenantHasSpots, total } = await this.withLoader(() => spotService.fetchSpots(filters) ); - this.setSpots(response.spots.map((spot: any) => new Spot(spot))); - this.setTotal(response.total); + this.setSpots(spots.map((spot: any) => new Spot(spot))); + this.setTotal(total); + this.setTenantHasSpots(tenantHasSpots); }; + setTenantHasSpots(hasSpots: boolean) { + this.tenantHasSpots = hasSpots; + } + async fetchSpotById(id: string) { try { const response = await this.withLoader(() => diff --git a/frontend/app/services/spotService.ts b/frontend/app/services/spotService.ts index 55e5273a3..32f0fa958 100644 --- a/frontend/app/services/spotService.ts +++ b/frontend/app/services/spotService.ts @@ -33,6 +33,7 @@ interface AddCommentRequest { interface GetSpotsResponse { spots: SpotInfo[]; total: number; + tenantHasSpots: boolean; } interface GetSpotsRequest { diff --git a/frontend/app/utils/index.ts b/frontend/app/utils/index.ts index d27741ed6..513bd584d 100644 --- a/frontend/app/utils/index.ts +++ b/frontend/app/utils/index.ts @@ -504,7 +504,6 @@ export function truncateStringToFit(string: string, screenWidth: number, charWid let sendingRequest = false; export const handleSpotJWT = (jwt: string) => { - console.log(jwt, sendingRequest) let tries = 0; if (!jwt || sendingRequest) { return; diff --git a/spot/package.json b/spot/package.json index 7fee73f15..c970539bd 100644 --- a/spot/package.json +++ b/spot/package.json @@ -2,7 +2,7 @@ "name": "wxt-starter", "description": "manifest.json description", "private": true, - "version": "1.0.5", + "version": "1.0.6", "type": "module", "scripts": { "dev": "wxt",