diff --git a/config/webpack.config.js b/config/webpack.config.js index a84daec37..80166f883 100644 --- a/config/webpack.config.js +++ b/config/webpack.config.js @@ -133,7 +133,7 @@ const commonConfig = ({ dev }) => { }, ], }, - plugins: plugins(dev, process.env.BETA === 'true'), + plugins: plugins(dev, process.env.BETA === 'true', process.env.NODE_ENV === 'restricted'), devServer: { allowedHosts: 'all', headers: { diff --git a/config/webpack.plugins.js b/config/webpack.plugins.js index 0d63a21b6..fd014cdfb 100644 --- a/config/webpack.plugins.js +++ b/config/webpack.plugins.js @@ -12,7 +12,7 @@ const getDynamicModules = require('./get-dynamic-modules'); const deps = require('../package.json').dependencies; -const plugins = (dev = false, beta = false) => { +const plugins = (dev = false, beta = false, restricted = false) => { const ChunkMapper = new (require('./chunk-mapper'))({ modules: 'chrome', _unstableHotReload: dev, @@ -53,7 +53,7 @@ const plugins = (dev = false, beta = false) => { }), ChunkMapper, new HtmlWebpackPlugin({ - template: path.resolve(__dirname, '../src/index.ejs'), + template: restricted ? path.resolve(__dirname, '../src/indexRes.ejs') : path.resolve(__dirname, '../src/index.ejs'), inject: 'body', minify: false, filename: dev ? 'index.html' : '../index.html', diff --git a/package-lock.json b/package-lock.json index f28cfa6b3..e45a73400 100644 --- a/package-lock.json +++ b/package-lock.json @@ -20,7 +20,7 @@ "@patternfly/react-core": "^5.0.1", "@patternfly/react-icons": "^5.0.1", "@patternfly/react-tokens": "^5.0.1", - "@redhat-cloud-services/chrome": "^0.0.11", + "@redhat-cloud-services/chrome": "^1.0.2", "@redhat-cloud-services/entitlements-client": "1.2.0", "@redhat-cloud-services/frontend-components": "^4.0.10", "@redhat-cloud-services/frontend-components-notifications": "^4.0.2", @@ -3017,12 +3017,13 @@ } }, "node_modules/@redhat-cloud-services/chrome": { - "version": "0.0.11", - "resolved": "https://registry.npmjs.org/@redhat-cloud-services/chrome/-/chrome-0.0.11.tgz", - "integrity": "sha512-qnSouKBlFgJDREdOotCUh9G69Xi7qNo1/BnkcJEJ8QQGavu36YnV3MehPKE7XE8igRdMqwcz5DCd29fmS8rCFg==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@redhat-cloud-services/chrome/-/chrome-1.0.2.tgz", + "integrity": "sha512-NDmtDcrRspMuuPlgEFMgYokj3B3w1xkUdeAlatSzF5Y2eNl3DMJpE3/DMNL+gFDq7U7S/7pu/EODGym7yz07Pg==", "peerDependencies": { - "react": "^18.0.0", - "react-dom": "^18.0.0", + "@scalprum/react-core": "^0.5.1", + "react": "^18.2.0", + "react-dom": "^18.2.0", "react-router-dom": "^6.0.0" } }, @@ -29456,9 +29457,9 @@ } }, "@redhat-cloud-services/chrome": { - "version": "0.0.11", - "resolved": "https://registry.npmjs.org/@redhat-cloud-services/chrome/-/chrome-0.0.11.tgz", - "integrity": "sha512-qnSouKBlFgJDREdOotCUh9G69Xi7qNo1/BnkcJEJ8QQGavu36YnV3MehPKE7XE8igRdMqwcz5DCd29fmS8rCFg==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@redhat-cloud-services/chrome/-/chrome-1.0.2.tgz", + "integrity": "sha512-NDmtDcrRspMuuPlgEFMgYokj3B3w1xkUdeAlatSzF5Y2eNl3DMJpE3/DMNL+gFDq7U7S/7pu/EODGym7yz07Pg==", "requires": {} }, "@redhat-cloud-services/entitlements-client": { diff --git a/package.json b/package.json index b96784eca..94e294116 100644 --- a/package.json +++ b/package.json @@ -12,6 +12,7 @@ "build": "NODE_ENV=production webpack --config config/webpack.config.js --mode=production", "build:beta": "BETA=true npm run build", "build:dev": "NODE_ENV=development webpack --config config/webpack.config.js --mode=development", + "build:res": "NODE_ENV=restricted webpack --config config/webpack.config.js --mode=production", "cypress": "cypress", "cypress:run": "cypress run --browser electron", "dev": "DEV_SERVER=true webpack serve --config config/webpack.config.js --mode=development", @@ -134,7 +135,7 @@ "@patternfly/react-core": "^5.0.1", "@patternfly/react-icons": "^5.0.1", "@patternfly/react-tokens": "^5.0.1", - "@redhat-cloud-services/chrome": "^0.0.11", + "@redhat-cloud-services/chrome": "^1.0.2", "@redhat-cloud-services/entitlements-client": "1.2.0", "@redhat-cloud-services/frontend-components": "^4.0.10", "@redhat-cloud-services/frontend-components-notifications": "^4.0.2", diff --git a/src/auth/index.ts b/src/auth/index.ts index 0005a535c..559fc44a0 100644 --- a/src/auth/index.ts +++ b/src/auth/index.ts @@ -5,7 +5,7 @@ import { ChromeUser } from '@redhat-cloud-services/types'; import { Store } from 'redux'; import * as jwt from '../jwt/jwt'; -import { getTokenWithAuthorizationCode } from '../cognito/auth'; +import { createUser, getTokenWithAuthorizationCode } from '../cognito/auth'; import { ITLessCognito } from '../utils/common'; import consts, { defaultAuthOptions as defaultOptions } from '../utils/consts'; import { ACCOUNT_REQUEST_TIMEOUT, ACTIVE_REMOTE_REQUEST, CROSS_ACCESS_ACCOUNT_NUMBER, CROSS_ACCESS_ORG_ID } from '../utils/consts'; @@ -59,10 +59,14 @@ export const createAuthObject = (libjwt: LibJWT, getUser: () => Promise Promise) => { - return () => - libjwt.initPromise.then(libjwt.jwt.getUserInfo).catch(() => { - libjwt.jwt.logoutAllTabs(); - }); + if (isITLessCognito) { + return () => createUser(); + } else { + return () => + libjwt.initPromise.then(libjwt.jwt.getUserInfo).catch(() => { + libjwt.jwt.logoutAllTabs(); + }); + } }; export const createGetUserPermissions = (libJwt: LibJWT, getUser: () => Promise) => { diff --git a/src/bootstrap.tsx b/src/bootstrap.tsx index 7c808a97c..c5d971bfa 100644 --- a/src/bootstrap.tsx +++ b/src/bootstrap.tsx @@ -22,6 +22,7 @@ import initializeJWT from './jwt/initialize-jwt'; import AppPlaceholder from './components/AppPlaceholder'; import { initializeVisibilityFunctions } from './utils/VisibilitySingleton'; import { createGetUser } from './auth'; +import { getTokenWithAuthorizationCode } from './cognito/auth'; const language: keyof typeof messages = 'en'; @@ -46,16 +47,18 @@ const initializeAccessRequestCookies = () => { const libjwtSetup = (chromeConfig: { ssoUrl?: string }, ssoScopes: string[] = []) => { const libjwt = auth({ ...chromeConfig, ssoScopes } || { ssoScopes }); - libjwt.initPromise.then(() => { - return libjwt.jwt - .getUserInfo() - .then((chromeUser) => { - if (chromeUser) { - sentry(chromeUser); - } - }) - .catch(noop); - }); + if (!ITLess()) { + libjwt.initPromise.then(() => { + return libjwt.jwt + .getUserInfo() + .then((chromeUser) => { + if (chromeUser) { + sentry(chromeUser); + } + }) + .catch(noop); + }); + } return libjwt; }; @@ -96,7 +99,10 @@ const useInitialize = () => { const getUser = createGetUser(libJwt); initializeVisibilityFunctions({ getUser, - getToken: () => libJwt!.initPromise.then(() => libJwt!.jwt.getUserInfo().then(() => libJwt!.jwt.getEncodedToken())), + getToken: () => + ITLessCognito() + ? getTokenWithAuthorizationCode() + : libJwt!.initPromise.then(() => libJwt!.jwt.getUserInfo().then(() => libJwt!.jwt.getEncodedToken())), getUserPermissions: createGetUserPermissions(libJwt, getUser), }); diff --git a/src/components/Header/Tools.tsx b/src/components/Header/Tools.tsx index dc37dcb95..bf6b8685d 100644 --- a/src/components/Header/Tools.tsx +++ b/src/components/Header/Tools.tsx @@ -27,6 +27,7 @@ import { ReduxState } from '../../redux/store'; import BellIcon from '@patternfly/react-icons/dist/dynamic/icons/bell-icon'; import { toggleNotificationsDrawer } from '../../redux/actions'; import useWindowWidth from '../../hooks/useWindowWidth'; +import { usePreviewFlag } from '../../utils/usePreviewFlag'; const isITLessEnv = ITLess(); @@ -80,6 +81,7 @@ const Tools = () => { isRhosakEntitled: false, isDemoAcc: false, }); + const enableIntegrations = usePreviewFlag('platform.sources.integrations'); const { xs } = useWindowWidth(); const user = useSelector(({ chrome: { user } }: ReduxState) => user!); const unreadNotifications = useSelector(({ chrome: { notifications } }: ReduxState) => notifications.data.some((item) => !item.read)); @@ -88,7 +90,7 @@ const Tools = () => { const libjwt = useContext(LibtJWTContext); const intl = useIntl(); const location = useLocation(); - const settingsPath = isITLessEnv ? `/settings/my-user-access` : `/settings/sources`; + const settingsPath = isITLessEnv ? `/settings/my-user-access` : enableIntegrations ? `/settings/integrations` : '/settings/sources'; const identityAndAccessManagmentPath = '/iam/user-access/users'; const betaSwitcherTitle = `${isBeta() ? intl.formatMessage(messages.stopUsing) : intl.formatMessage(messages.use)} ${intl.formatMessage( messages.betaRelease diff --git a/src/components/RootApp/RootApp.tsx b/src/components/RootApp/RootApp.tsx index d5bf3a06e..bd83445b4 100644 --- a/src/components/RootApp/RootApp.tsx +++ b/src/components/RootApp/RootApp.tsx @@ -1,7 +1,6 @@ import React, { Suspense, lazy, memo, useEffect } from 'react'; import { unstable_HistoryRouter as HistoryRouter, HistoryRouterProps } from 'react-router-dom'; import { HelpTopicContainer, QuickStart, QuickStartContainer, QuickStartContainerProps } from '@patternfly/quickstarts'; -import { ChromeProvider } from '@redhat-cloud-services/chrome'; import chromeHistory from '../../utils/chromeHistory'; import { FeatureFlagsProvider } from '../FeatureFlags'; import ScalprumRoot from './ScalprumRoot'; @@ -15,7 +14,6 @@ import SegmentProvider from '../../analytics/SegmentProvider'; import { ReduxState } from '../../redux/store'; import { AppsConfig } from '@scalprum/core'; import { ITLess, chunkLoadErrorRefreshKey, getRouterBasename } from '../../utils/common'; -import useBundle from '../../hooks/useBundle'; import useUserSSOScopes from '../../hooks/useUserSSOScopes'; import { DeepRequired } from 'utility-types'; import ReactDOM from 'react-dom'; @@ -40,7 +38,6 @@ const RootApp = memo((props: RootAppProps) => { }, }: ReduxState) => Object.values(quickstarts).flat() ); - const { bundleTitle } = useBundle(); const user = useSelector(({ chrome }: DeepRequired) => chrome.user); const isDebuggerEnabled = useSelector(({ chrome: { isDebuggerEnabled } }) => isDebuggerEnabled); @@ -122,13 +119,11 @@ const RootApp = memo((props: RootAppProps) => { {user?.identity?.account_number && !ITLess() && isDebuggerEnabled && ReactDOM.createPortal(, document.body)} - - - - - - - + + + + + diff --git a/src/components/RootApp/ScalprumRoot.tsx b/src/components/RootApp/ScalprumRoot.tsx index b12d2d58d..f5fb7aa80 100644 --- a/src/components/RootApp/ScalprumRoot.tsx +++ b/src/components/RootApp/ScalprumRoot.tsx @@ -7,6 +7,7 @@ import { HelpTopic, HelpTopicContext } from '@patternfly/quickstarts'; import isEqual from 'lodash/isEqual'; import { AppsConfig } from '@scalprum/core'; import { ChromeAPI, EnableTopicsArgs } from '@redhat-cloud-services/types'; +import { ChromeProvider } from '@redhat-cloud-services/chrome'; import chromeHistory from '../../utils/chromeHistory'; import DefaultLayout from '../../layouts/DefaultLayout'; @@ -195,42 +196,44 @@ const ScalprumRoot = memo( */ - - } {...props} />} - /> - - - - } - /> - - } /> - - } - /> - {!ITLess() && ( + + + } {...props} />} + /> + + + + } + /> - } /> + } /> } /> - )} - {ITLess() && } />} - } /> - } /> - + {!ITLess() && ( + + } /> + + } + /> + )} + {ITLess() && } />} + } /> + } /> + + ); diff --git a/src/components/Routes/Routes.tsx b/src/components/Routes/Routes.tsx index 4481db2e5..b547decd9 100644 --- a/src/components/Routes/Routes.tsx +++ b/src/components/Routes/Routes.tsx @@ -1,10 +1,13 @@ -import React, { Suspense, lazy } from 'react'; +import React, { Suspense, lazy, useMemo } from 'react'; import { useSelector } from 'react-redux'; import { Navigate, Route, Routes } from 'react-router-dom'; import ChromeRoute from '../ChromeRoute'; import NotFoundRoute from '../NotFoundRoute'; import LoadingFallback from '../../utils/loading-fallback'; import { ReduxState } from '../../redux/store'; +import { usePreviewFlag } from '../../utils/usePreviewFlag'; + +const INTEGRATION_SOURCES = 'platform.sources.integrations'; const QuickstartCatalogRoute = lazy(() => import('../QuickstartsCatalogRoute')); @@ -17,9 +20,25 @@ const redirects = [ path: '/docs', to: '/api/docs', }, + { + path: '/settings', + to: '/settings/integrations', + previewFlag: { + value: true, + name: INTEGRATION_SOURCES, + }, + }, { path: '/settings', to: '/settings/sources', + previewFlag: { + value: false, + name: INTEGRATION_SOURCES, + }, + }, + { + path: '/user-preferences', + to: '/user-preferences/notifications', }, { path: '/quay', @@ -48,6 +67,8 @@ export type RoutesProps = { }; const ChromeRoutes = ({ routesProps }: RoutesProps) => { + const enableIntegrations = usePreviewFlag(INTEGRATION_SOURCES); + const previewFlags = useMemo>(() => ({ INTEGRATION_SOURCES: enableIntegrations }), [enableIntegrations]); const moduleRoutes = useSelector(({ chrome: { moduleRoutes } }: ReduxState) => moduleRoutes); const showBundleCatalog = localStorage.getItem('chrome:experimental:quickstarts') === 'true'; @@ -63,9 +84,15 @@ const ChromeRoutes = ({ routesProps }: RoutesProps) => { } /> )} - {redirects.map(({ path, to }) => ( - } /> - ))} + {redirects.map(({ path, to, previewFlag }) => { + if (previewFlag) { + const found = Object.keys(previewFlags).find((item) => item === previewFlag.name); + if (previewFlags[found as string] !== previewFlag.value) { + return null; + } + } + return } />; + })} {moduleRoutes.map((app) => ( } /> ))} diff --git a/src/indexRes.ejs b/src/indexRes.ejs new file mode 100644 index 000000000..2ce2671d7 --- /dev/null +++ b/src/indexRes.ejs @@ -0,0 +1,30 @@ + + + + + + + Hybrid Cloud Console + + + + + + + + + + + + + +
+ + + diff --git a/src/jwt/initialize-jwt.ts b/src/jwt/initialize-jwt.ts index 98e05eabf..885c28573 100644 --- a/src/jwt/initialize-jwt.ts +++ b/src/jwt/initialize-jwt.ts @@ -1,22 +1,37 @@ import { ChromeUser } from '@redhat-cloud-services/types'; import { LibJWT } from '../auth'; import { spinUpStore } from '../redux/redux-config'; +import { ITLessCognito } from '../utils/common'; +import { createUser, getTokenWithAuthorizationCode } from '../cognito/auth'; const initializeJWT = async (libjwt: LibJWT) => { const { actions } = spinUpStore(); - try { - await libjwt.initPromise; - const user = await libjwt.jwt.getUserInfo(); - if (user) { - actions.userLogIn(user as ChromeUser); + if (ITLessCognito()) { + try { + await getTokenWithAuthorizationCode(); + const user = await createUser(); + if (user) { + actions.userLogIn(user as ChromeUser); + } + } catch (error) { + console.error(error); + actions.userLogIn(false); } - const encodedToken = libjwt.jwt.getEncodedToken(); - if (encodedToken) { - // chromeInstance.cache = new CacheAdapter('chrome-store', `${decodeToken(encodedToken).session_state}-chrome-store`); + } else { + try { + await libjwt.initPromise; + const user = await libjwt.jwt.getUserInfo(); + if (user) { + actions.userLogIn(user as ChromeUser); + } + const encodedToken = libjwt.jwt.getEncodedToken(); + if (encodedToken) { + // chromeInstance.cache = new CacheAdapter('chrome-store', `${decodeToken(encodedToken).session_state}-chrome-store`); + } + } catch (error) { + console.error(error); + actions.userLogIn(false); } - } catch (error) { - console.error(error); - actions.userLogIn(false); } }; diff --git a/src/jwt/jwt.ts b/src/jwt/jwt.ts index d526504ea..2501a2b43 100644 --- a/src/jwt/jwt.ts +++ b/src/jwt/jwt.ts @@ -4,6 +4,7 @@ import { BroadcastChannel } from 'broadcast-channel'; import cookie from 'js-cookie'; import { DEFAULT_SSO_ROUTES, + ITLess, ITLessCognito, ITLessKeycloak, LOGIN_SCOPES_STORAGE_KEY, @@ -136,7 +137,7 @@ export const doOffline = (key: string, val: string, configSsoUrl?: string) => { scopes.push(partnerScope); } - if (ssoScopes && !itLessKeycloakEnv) { + if (ssoScopes && !ITLess()) { try { // make sure add openid scope when custom scope is used scopes.push('openid', JSON.parse(ssoScopes)); diff --git a/src/utils/common.ts b/src/utils/common.ts index 692669609..690667db2 100644 --- a/src/utils/common.ts +++ b/src/utils/common.ts @@ -32,15 +32,15 @@ export const DEFAULT_SSO_ROUTES = { sso: 'https://sso.stage.redhat.com/auth', portal: 'https://access.stage.redhat.com', }, - frh: { + frhStage: { url: ['console.stage.openshiftusgov.com'], sso: 'https://ocm-ra-stage-domain.auth-fips.us-gov-west-1.amazoncognito.com/login', portal: 'https://console.stage.openshiftusgov.com', }, - frhStage: { - url: ['console.stage.openshiftusgov.com'], + frh: { + url: ['console.openshiftusgov.com'], sso: 'https://ocm-ra-stage-domain.auth-fips.us-gov-west-1.amazoncognito.com/login', - portal: 'https://console.stage.openshiftusgov.com', + portal: 'https://console.openshiftusgov.com', }, ephem: { url: ['ephem.outsrights.cc'], @@ -211,11 +211,11 @@ export function getRouterBasename(pathname?: string) { } export function ITLess() { - return getEnv() === 'frh' || getEnv() === 'frhStage' || getEnv() === 'ephem' || getEnv() === 'int' || getEnv() === 'scr'; + return getEnv() === 'frhStage' || getEnv() === 'frh' || getEnv() === 'ephem' || getEnv() === 'int' || getEnv() === 'scr'; } export function ITLessCognito() { - return getEnv() === 'frh' || getEnv() === 'frhStage'; + return getEnv() === 'frhStage' || getEnv() === 'frh'; } export function ITLessKeycloak() { diff --git a/src/utils/fetchNavigationFiles.ts b/src/utils/fetchNavigationFiles.ts index 45cbabd86..30067e936 100644 --- a/src/utils/fetchNavigationFiles.ts +++ b/src/utils/fetchNavigationFiles.ts @@ -2,13 +2,13 @@ import axios from 'axios'; import { BundleNavigation, NavItem, Navigation } from '../@types/types'; import { Required } from 'utility-types'; import { itLessBundles, requiredBundles } from '../components/AppFilter/useAppFilter'; -import { ITLessKeycloak, getChromeStaticPathname, isBeta } from './common'; +import { ITLess, getChromeStaticPathname, isBeta } from './common'; export function isBundleNavigation(item: unknown): item is BundleNavigation { return typeof item !== 'undefined'; } -const bundles = ITLessKeycloak() ? itLessBundles : requiredBundles; +const bundles = ITLess() ? itLessBundles : requiredBundles; export function isNavItems(navigation: Navigation | NavItem[]): navigation is Navigation { return Array.isArray((navigation as Navigation).navItems); diff --git a/src/utils/usePreviewFlag.ts b/src/utils/usePreviewFlag.ts new file mode 100644 index 000000000..e28a3a958 --- /dev/null +++ b/src/utils/usePreviewFlag.ts @@ -0,0 +1,12 @@ +import { useFlag } from '@unleash/proxy-client-react'; +import { isBeta, isProd } from './common'; + +export const usePreviewFlag = (flag: string) => { + const notificationsOverhaul = useFlag(flag); + + if (isProd() && !isBeta()) { + return false; + } + + return notificationsOverhaul; +};