Skip to content

Commit

Permalink
Merge pull request #2835 from Hyperkid123/end-preview
Browse files Browse the repository at this point in the history
End preview
  • Loading branch information
Hyperkid123 authored Jun 19, 2024
2 parents 1873fab + d4ed4b7 commit 88212d3
Show file tree
Hide file tree
Showing 46 changed files with 536 additions and 227 deletions.
2 changes: 1 addition & 1 deletion cypress.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ export default defineConfig({
},
e2e: {
blockHosts: ['consent.trustarc.com'],
baseUrl: 'https://stage.foo.redhat.com:1337/beta',
baseUrl: 'https://stage.foo.redhat.com:1337/',
env: {
E2E_USER: process.env.E2E_USER,
E2E_PASSWORD: process.env.E2E_PASSWORD,
Expand Down
41 changes: 25 additions & 16 deletions cypress/component/AllServicesPage/AllServicesPage.cy.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ import { ScalprumProvider } from '@scalprum/react-core';
import { getVisibilityFunctions, initializeVisibilityFunctions } from '../../../src/utils/VisibilitySingleton';
import userFixture from '../../fixtures/testUser.json';
import { ChromeUser } from '@redhat-cloud-services/types';
import { FeatureFlagsProvider } from '../../../src/components/FeatureFlags';
import ChromeAuthContext from '../../../src/auth/ChromeAuthContext';

describe('<AllServices />', () => {
beforeEach(() => {
Expand All @@ -31,6 +33,7 @@ describe('<AllServices />', () => {

it('should filter by service category title', () => {
initializeVisibilityFunctions({
isPreview: false,
getToken: () => Promise.resolve(''),
getUser: () => Promise.resolve(userFixture as unknown as ChromeUser),
getUserPermissions: () => Promise.resolve([]),
Expand All @@ -48,22 +51,28 @@ describe('<AllServices />', () => {
},
}));
cy.mount(
<ScalprumProvider
config={{}}
api={{
chrome: {
visibilityFunctions,
},
}}
>
<BrowserRouter>
<Provider store={store}>
<IntlProvider locale="en">
<AllServices />
</IntlProvider>
</Provider>
</BrowserRouter>
</ScalprumProvider>
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
<ChromeAuthContext.Provider value={{}}>
<ScalprumProvider
config={{}}
api={{
chrome: {
visibilityFunctions,
},
}}
>
<BrowserRouter>
<FeatureFlagsProvider>
<Provider store={store}>
<IntlProvider locale="en">
<AllServices />
</IntlProvider>
</Provider>
</FeatureFlagsProvider>
</BrowserRouter>
</ScalprumProvider>
</ChromeAuthContext.Provider>
);

cy.get('.pf-v5-c-text-input-group__text-input').type('consoleset');
Expand Down
3 changes: 2 additions & 1 deletion cypress/e2e/auth/OIDC/OIDCState.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,11 @@ describe('OIDC State', () => {
// Enable cypress exceptions again
return true;
});
cy.wait(1000);
// The reloader should preserve pathname and query params
const url = new URL(win.location.href);
expect(url.hash).to.be.empty;
expect(url.pathname).to.eq('/beta/foo/bar');
expect(url.pathname).to.eq('/foo/bar');
expect(url.search).to.eq('?baz=quaz');
cy.contains('Insights QA').should('exist');
});
Expand Down
24 changes: 13 additions & 11 deletions src/analytics/SegmentProvider.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React, { useContext, useEffect, useRef } from 'react';
import { AnalyticsBrowser } from '@segment/analytics-next';
import Cookie from 'js-cookie';
import { ITLess, isBeta, isProd } from '../utils/common';
import { ITLess, isProd } from '../utils/common';
import { ChromeUser } from '@redhat-cloud-services/types';
import { useLocation } from 'react-router-dom';
import axios from 'axios';
Expand All @@ -11,6 +11,7 @@ import { getUrl } from '../hooks/useBundle';
import ChromeAuthContext from '../auth/ChromeAuthContext';
import { useAtomValue } from 'jotai';
import { activeModuleAtom, activeModuleDefinitionReadAtom } from '../state/atoms/activeModuleAtom';
import { isPreviewAtom } from '../state/atoms/releaseAtom';

type SegmentEnvs = 'dev' | 'prod';
type SegmentModules = 'acs' | 'openshift' | 'hacCore';
Expand All @@ -31,7 +32,7 @@ function getAdobeVisitorId() {
return -1;
}

const getPageEventOptions = () => {
const getPageEventOptions = (isPreview: boolean) => {
const path = window.location.pathname.replace(/^\/(beta\/|preview\/|beta$|preview$)/, '/');
const search = new URLSearchParams(window.location.search);

Expand All @@ -46,7 +47,7 @@ const getPageEventOptions = () => {
{
path,
url: `${window.location.origin}${path}${window.location.search}`,
isBeta: isBeta(),
isBeta: isPreview,
module: window._segment?.activeModule,
// Marketing campaing tracking
...trackingContext,
Expand Down Expand Up @@ -77,7 +78,7 @@ const getAPIKey = (env: SegmentEnvs = 'dev', module: SegmentModules, moduleAPIKe
KEY_FALLBACK[env];

let observer: MutationObserver | undefined;
const registerAnalyticsObserver = () => {
const registerAnalyticsObserver = (isPreview: boolean) => {
// never override the observer
if (observer) {
return;
Expand All @@ -96,7 +97,7 @@ const registerAnalyticsObserver = () => {
oldHref = newLocation;
window?.sendCustomEvent?.('pageBottom');
setTimeout(() => {
window.segment?.page(...getPageEventOptions());
window.segment?.page(...getPageEventOptions(isPreview));
});
}
});
Expand All @@ -113,7 +114,7 @@ const emailDomain = (email = '') => (/@/g.test(email) ? email.split('@')[1].toLo

const getPagePathSegment = (pathname: string, n: number) => pathname.split('/')[n] || '';

const getIdentityTraits = (user: ChromeUser, pathname: string, activeModule = '') => {
const getIdentityTraits = (user: ChromeUser, pathname: string, activeModule = '', isPreview: boolean) => {
const entitlements = Object.entries(user.entitlements).reduce(
(acc, [key, entitlement]) => ({
...acc,
Expand All @@ -132,7 +133,7 @@ const getIdentityTraits = (user: ChromeUser, pathname: string, activeModule = ''
isOrgAdmin: user.identity.user?.is_org_admin,
currentBundle: getUrl('bundle'),
currentApp: activeModule,
isBeta: isBeta(),
isBeta: isPreview,
...(user.identity.user
? {
name: `${user.identity.user.first_name} ${user.identity.user.last_name}`,
Expand All @@ -158,6 +159,7 @@ const SegmentProvider: React.FC<React.PropsWithChildren> = ({ children }) => {
const analytics = useRef<AnalyticsBrowser>();
const analyticsLoaded = useRef(false);
const { user } = useContext(ChromeAuthContext);
const isPreview = useAtomValue(isPreviewAtom);

const activeModule = useAtomValue(activeModuleAtom);
const activeModuleDefinition = useAtomValue(activeModuleDefinitionReadAtom);
Expand Down Expand Up @@ -198,7 +200,7 @@ const SegmentProvider: React.FC<React.PropsWithChildren> = ({ children }) => {
activeModule,
};
const newKey = getAPIKey(DEV_ENV ? 'dev' : 'prod', activeModule as SegmentModules, moduleAPIKey);
const identityTraits = getIdentityTraits(user, pathname, activeModule);
const identityTraits = getIdentityTraits(user, pathname, activeModule, isPreview);
const identityOptions = {
context: {
groupId: user.identity.internal?.org_id,
Expand Down Expand Up @@ -226,7 +228,7 @@ const SegmentProvider: React.FC<React.PropsWithChildren> = ({ children }) => {
},
});
analytics.current.group(user.identity.internal?.org_id, groupTraits);
analytics.current.page(...getPageEventOptions());
analytics.current.page(...getPageEventOptions(isPreview));
initialized.current = true;
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
//@ts-ignore TS does not allow accessing the instance settings but its necessary for us to not create instances if we don't have to
Expand Down Expand Up @@ -259,12 +261,12 @@ const SegmentProvider: React.FC<React.PropsWithChildren> = ({ children }) => {
};

useEffect(() => {
registerAnalyticsObserver();
registerAnalyticsObserver(isPreview);
return () => {
observer?.disconnect();
observer = undefined;
};
}, []);
}, [isPreview]);

useEffect(() => {
handleModuleUpdate();
Expand Down
6 changes: 3 additions & 3 deletions src/analytics/analytics.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ function buildUser(token: any): DeepRequired<ChromeUser> {
describe('User + Analytics', () => {
describe('buildUser + getPendoConf internal', () => {
test('should build a valid internal Pendo config', () => {
const conf = getPendoConf(buildUser(token));
const conf = getPendoConf(buildUser(token), false);
expect(conf).toMatchObject({
account: {
id: '540155',
Expand All @@ -47,7 +47,7 @@ describe('User + Analytics', () => {
});

test('should build a valid external Pendo config', () => {
const conf = getPendoConf(buildUser(externalToken));
const conf = getPendoConf(buildUser(externalToken), false);
expect(conf).toMatchObject({
account: {
id: '540155',
Expand All @@ -61,7 +61,7 @@ describe('User + Analytics', () => {
});

test('should build a valid IBM pendo config', () => {
const conf = getPendoConf(buildUser(ibmToken));
const conf = getPendoConf(buildUser(ibmToken), false);
expect(conf).toMatchObject({
account: {
id: '540155',
Expand Down
15 changes: 7 additions & 8 deletions src/analytics/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { isBeta, isProd } from '../utils/common';
import { isProd } from '../utils/common';
import { ChromeUser } from '@redhat-cloud-services/types';
import { DeepRequired } from 'utility-types';

Expand All @@ -14,23 +14,22 @@ function isInternalFlag(email: string, isInternal = false) {
return '';
}

function getUrl(type?: string) {
function getUrl(type?: string, isPreview = false) {
if (['/beta', '/preview', '/'].includes(window.location.pathname)) {
return 'landing';
}

const sections = window.location.pathname.split('/').slice(1);
const isBetaEnv = isBeta();
if (type) {
if (isBetaEnv) {
if (isPreview) {
return type === 'bundle' ? sections[1] : sections[2];
}

return type === 'bundle' ? sections[0] : sections[1];
}

isBetaEnv && sections.shift();
return [isBetaEnv, ...sections];
isPreview && sections.shift();
return [isPreview, ...sections];
}

function getAdobeVisitorId() {
Expand All @@ -42,7 +41,7 @@ function getAdobeVisitorId() {
return -1;
}

export function getPendoConf(data: DeepRequired<ChromeUser>) {
export function getPendoConf(data: DeepRequired<ChromeUser>, isPreview: boolean) {
const userID = `${data.identity.internal.account_id}${isInternalFlag(data.identity.user.email, data.identity.user.is_internal)}`;

const entitlements: Record<string, boolean> = {};
Expand All @@ -53,7 +52,7 @@ export function getPendoConf(data: DeepRequired<ChromeUser>) {
entitlements[`entitlements_${key}_trial`] = value.is_trial;
});

const [isBeta, currentBundle, currentApp, ...rest] = getUrl();
const [isBeta, currentBundle, currentApp, ...rest] = getUrl(undefined, isPreview);

return {
visitor: {
Expand Down
4 changes: 3 additions & 1 deletion src/auth/OIDCConnector/OIDCProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@ import AppPlaceholder from '../../components/AppPlaceholder';
import { postbackUrlSetup } from '../offline';
import OIDCStateReloader from './OIDCStateReloader';

const betaPartial = isBeta() ? '/beta' : '';
const LOCAL_PREVIEW = localStorage.getItem('chrome:local-preview') === 'true';
// TODO: remove this once the local preview is enabled by default
const betaPartial = LOCAL_PREVIEW ? '' : isBeta() ? '/beta' : '';

const OIDCProvider: React.FC<React.PropsWithChildren> = ({ children }) => {
const [cookieElement, setCookieElement] = useState<HTMLAnchorElement | null>(null);
Expand Down
7 changes: 0 additions & 7 deletions src/auth/OIDCConnector/OIDCSecured.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,11 @@ import { generateRoutesList } from '../../utils/common';
import getInitialScope from '../getInitialScope';
import { init } from '../../utils/iqeEnablement';
import entitlementsApi from '../entitlementsApi';
import { initializeVisibilityFunctions } from '../../utils/VisibilitySingleton';
import sentry from '../../utils/sentry';
import AppPlaceholder from '../../components/AppPlaceholder';
import { FooterProps } from '../../components/Footer/Footer';
import logger from '../logger';
import { login, logout } from './utils';
import createGetUserPermissions from '../createGetUserPermissions';
import initializeAccessRequestCookies from '../initializeAccessRequestCookies';
import { getOfflineToken, prepareOfflineRedirect } from '../offline';
import { OFFLINE_REDIRECT_STORAGE_KEY } from '../../utils/consts';
Expand Down Expand Up @@ -151,11 +149,6 @@ export function OIDCSecured({
const entitlements = await fetchEntitlements(user);
const chromeUser = mapOIDCUserToChromeUser(user, entitlements);
const getUser = () => Promise.resolve(chromeUser);
initializeVisibilityFunctions({
getUser,
getToken: () => Promise.resolve(user.access_token),
getUserPermissions: createGetUserPermissions(getUser, () => Promise.resolve(user.access_token)),
});
setState((prev) => ({
...prev,
ready: true,
Expand Down
1 change: 1 addition & 0 deletions src/auth/OIDCConnector/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ export async function logout(auth: AuthContextProps, bounce?: boolean) {
key.startsWith(GLOBAL_FILTER_KEY)
);
deleteLocalStorageItems([...keys, OFFLINE_REDIRECT_STORAGE_KEY, LOGIN_SCOPES_STORAGE_KEY]);
// FIXME: Remove this one local preview is enabled by default
const pathname = isBeta() ? getRouterBasename() : '';
if (bounce) {
const eightSeconds = new Date(new Date().getTime() + 8 * 1000);
Expand Down
37 changes: 33 additions & 4 deletions src/bootstrap.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import React, { useEffect, useMemo, useState } from 'react';
import React, { Suspense, useContext, useEffect, useMemo, useState } from 'react';
import { createRoot } from 'react-dom/client';
import { Provider, useSelector } from 'react-redux';
import { IntlProvider, ReactIntlErrorCode } from 'react-intl';
import { Provider as JotaiProvider } from 'jotai';
import { Provider as JotaiProvider, useSetAtom } from 'jotai';

import { spinUpStore } from './redux/redux-config';
import RootApp from './components/RootApp';
Expand All @@ -14,6 +14,11 @@ import messages from './locales/data.json';
import ErrorBoundary from './components/ErrorComponents/ErrorBoundary';
import chromeStore from './state/chromeStore';
import { GenerateId } from '@patternfly/react-core/dist/dynamic/helpers/GenerateId/GenerateId';
import { isPreviewAtom } from './state/atoms/releaseAtom';
import AppPlaceholder from './components/AppPlaceholder';
import useAsyncLoader from './hooks/useAsyncLoader';
import { ChromeUserConfig, initChromeUserConfig } from './utils/initUserConfig';
import ChromeAuthContext from './auth/ChromeAuthContext';

const isITLessEnv = ITLess();
const language: keyof typeof messages = 'en';
Expand All @@ -34,7 +39,14 @@ const useInitializeAnalytics = () => {
}, []);
};

const App = () => {
const App = ({ initApp }: { initApp: (...args: Parameters<typeof initChromeUserConfig>) => ChromeUserConfig | undefined }) => {
const { getUser, token } = useContext(ChromeAuthContext);
// triggers suspense based async call to block rendering until the async call is resolved
// TODO: Most of async init should be moved to this method
initApp({
getUser,
token,
});
const documentTitle = useSelector(({ chrome }: ReduxState) => chrome?.documentTitle);
const [cookieElement, setCookieElement] = useState<HTMLAnchorElement | null>(null);

Expand All @@ -48,6 +60,23 @@ const App = () => {
return <RootApp cookieElement={cookieElement} setCookieElement={setCookieElement} />;
};

const ConfigLoader = () => {
const initPreview = useSetAtom(isPreviewAtom);
function initSuccess(userConfig: ChromeUserConfig) {
initPreview(userConfig.data.uiPreview);
}
function initFail() {
initPreview(false);
}
const { loader } = useAsyncLoader(initChromeUserConfig, initSuccess, initFail);
const [cookieElement, setCookieElement] = useState<HTMLAnchorElement | null>(null);
return (
<Suspense fallback={<AppPlaceholder cookieElement={cookieElement} setCookieElement={setCookieElement} />}>
<App initApp={loader} />
</Suspense>
);
};

const entry = document.getElementById('chrome-entry');
if (entry) {
const reactRoot = createRoot(entry);
Expand All @@ -69,7 +98,7 @@ if (entry) {
>
<ErrorBoundary>
<AuthProvider>
<App />
<ConfigLoader />
</AuthProvider>
</ErrorBoundary>
</IntlProvider>
Expand Down
Loading

0 comments on commit 88212d3

Please sign in to comment.