Skip to content

Commit

Permalink
Merge branch 'master' into mknop/RHCLOUD-27269-frontends-pipeline
Browse files Browse the repository at this point in the history
  • Loading branch information
maknop authored Sep 5, 2023
2 parents 18e5e9f + 441c3d5 commit bde9edd
Show file tree
Hide file tree
Showing 30 changed files with 356 additions and 302 deletions.
5 changes: 3 additions & 2 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
language: node_js
sudo: required
dist: jammy
notifications:
email: false
slack:
secure: 'd3g5oKl5kfzi2L96QTrj2g77lzLWzjnM6Ct2OTXRrk90GxxhwHS8RH4Q1IgBqkQjw68nkq7CNE9oAs+pt3si8kT4GQ164YLoTMVkDPBGOoOoMACPyanxQOEluUfdLEDIzChy/7EdlY3l1J2IM+lOK4e95jUwsT9BSXBsSladP++1EUiZfon9JcQSiSZa0e1/cVxLpEDuBB2cruUSTZ9sUATe/XZ0uH1EGzrooQJMkRgdty5UyNSsMxkvAY0Haivq8u9/gWAsLar0bA/90M5CVK7yohh9fY9UfTUbXVqwR3dFAXuW+SURrFVnPAX4FLZt/D09cg/CVCvoasiZdNi9RAeKOCfN+FoxB2ZJNnuM+4KDJX3dxnatd/stmEH1bcd75i4mh9zOWE1HX5d23HuZ4sKdDPpvhG3l7SpZfhLv0/EKL10ld9RdIaiTO2uPI3rsoyDeArzeV+09+dbB1iPKnS/3/Iw5KLhbew3mdJXKVfRk6KYcJySjT8EltrNy5Y7mty7/JzWssSpIpkMCnu6RGAtXO2v/jUfFm1WvsKK5BeH5efbLi1sjMNbVTeA3Bp8pvRPuw+50l94uDfeQ1HUTrq5zKXMUaG9dTdaYZX4fEDMmrbM1TLudjb9Xj4elaA5ioBH0gRFxAnSVTmrKFtFoCRVaqfmj3ceqxttCLUpkfvI='
node_js:
- '16'
- '18'
before_install:
- npm install -g npm@latest
install:
Expand Down Expand Up @@ -38,4 +39,4 @@ env:
cache:
directories:
- "$HOME/.npm"
- ".cache"
- ".cache"
2 changes: 1 addition & 1 deletion config/webpack.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,7 @@ const pfConfig = {
path: path.resolve(__dirname, '../build/js/pf'),
// the HMR needs dynamic entry filename to remove name conflicts
filename: '[name].js',
publicPath: `${publicPath}pf/`,
publicPath: `auto`,
},
plugins: [new MiniCssExtractPlugin()],
stats: {
Expand Down
69 changes: 69 additions & 0 deletions cypress/e2e/release-gate/search.cy.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
const searchResponse = {
response: {
numFound: 2,
start: 0,
maxScore: 10.0,
docs: [
{
id: 'hcc-module-/openshift/create-OPENSHIFT.cluster.create.azure',
view_uri: 'https://console.redhat.com/openshift/create',
documentKind: 'ModuleDefinition',
allTitle: 'Azure Red Hat OpenShift',
bundle: ['openshift'],
bundle_title: ['OpenShift'],
relative_uri: '/openshift/create',
alt_titles: ['ARO', 'Azure', 'OpenShift on Azure'],
abstract: 'https://console.redhat.com/openshift/create',
timestamp: '2023-08-22T17:01:31.717Z',
_version_: 1774949404248113152,
},
{
id: 'hcc-module-/openshift/releases-openshift.releases',
view_uri: 'https://console.redhat.com/openshift/releases',
documentKind: 'ModuleDefinition',
allTitle: 'Releases',
bundle: ['openshift'],
bundle_title: ['OpenShift'],
relative_uri: '/openshift/releases',
icons: 'InfrastructureIcon',
abstract: 'View general information on the most recent OpenShift Container Platform release versions that you can install.',
timestamp: '2023-08-15T10:55:46.769Z',
_version_: 1774949404248113152,
},
],
},
highlighting: {
'hcc-module-/openshift/create-OPENSHIFT.cluster.create.azure': {
abstract: ['https://console.redhat.com/<mark>openshift</mark>/create'],
allTitle: ['Azure Red Hat <mark>OpenShift</mark>'],
bundle: ['<mark>openshift</mark>'],
},
'hcc-module-/openshift/releases-openshift.releases': {
abstract: ['View general information on the most recent <mark>OpenShift</mark> Container Platform release versions that you can install.'],
allTitle: ['Releases'],
bundle: ['<mark>openshift</mark>'],
},
},
};

describe('Search', () => {
it('search for openshift services', () => {
cy.login();
cy.visit('/');
cy.intercept(
{
method: 'GET',
url: '**/hydra/rest/search/**',
},
searchResponse
).as('search');
cy.get('.chr-c-search__input').click().type('openshift');
cy.wait('@search').its('response.statusCode').should('equal', 200);
cy.get('@search.all').should('have.length', 1);
cy.screenshot();
cy.get('.chr-c-search__input').should('contain', 'Top 2 results');
cy.get('.chr-c-search__input li').first().should('contain', 'Azure');
cy.get('.chr-c-search__input li').last().should('contain', 'Releases').click();
cy.url().should('contain', '/openshift/releases');
});
});
77 changes: 40 additions & 37 deletions docs/localWSDevelopment.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

## Setting up the development environment

### Chrome service backend
### Chrome Service Backend

The chrome service backend is the bridge between kafka and the browser client. It exposes a WS endpoint that allows the browser to connect to the service.

Expand All @@ -18,14 +18,46 @@ The chrome service backend is the bridge between kafka and the browser client. I
To enable it for local development with chrome UI follow these steps:

1. Make sure you are on the `main` branch or have created new branch fro the latest `main`.
2. <a name="bypass"></a>If the WS feature is hidden behind a feature flag, and you don't want to go through the FF setup, [bypass this condition](https://github.com/RedHatInsights/chrome-service-backend/blob/main/main.go#L61) by adding `true || ..` to the condition in your local repository.
3. Start the kafka container by running `make kafka`.
4. Start the chrome service by running `go run .` in the repo root.
5. Run a `go run cmd/kafka/testMessage.go` to test the connection. You should see a log in the terminal from where the go server was started.
2. Start the kafka and unleash containers by running `make infra`.
3. Start the chrome service by running `make dev` in the repo root.
4. Run a `go run cmd/kafka/testMessage.go` to test the connection. You should see a log in the terminal from where the go server was started.

#### The `make kafka` command failed.

It is possible that you have services running on your machine that occupy either the kafka or postgres ports. To change the default values, open the `local/kafka-compose.yaml` and change the postgres or kafka (or both) port bindings:

### Chrome Frontend

1. Ensure you are on the latest version for chrome `master` branch. The support for WS client was added in [#2525](https://github.com/RedHatInsights/insights-chrome/pull/2525).
2. Once your chrome service backend is running, start the chrome dev server with the chrome service config using this command: `CHROME_SERVICE=8000 yarn dev`.
3. The WS client connection is hidden behind a `platform.chrome.notifications-drawer` feature flag. If its not available in your current environment (stage or prod or EE), bypass the feature flag condition in the `src/hooks/useChromeServiceEvents.ts` file.
4. Open the browser, open the browser console, emit a custom message from the chrome service terminal using `go run cmd/kafka/testMessage.go`.
5. In the network tab of your browser console, filter only to show `ws` communication, click on related ws connection (there will be a couple for webpack dev server, ignore these and find `wss://stage.foo.redhat.com:1337/wss/chrome-service/v1/ws`).
6. Click the 'messages' tab in chrome or the 'response' tab in firefox and observe the messages being pushed down to the browser. The messages should be similar to the sample payload below.

#### Sample WS message payload

```js
{
// the actual payload consumed by chrome
data: {
description: "Some longer description",
title: "New notification"
},
// cloud events sub protocol metadata
datacontenttype: "application/json",
id: "test-message",
source: "https://whatever.service.com",
specversion: "1.0.2",
time: "2023-05-23T11:54:03.879689005+02:00",
// a type field used to identify message purpose
type: "notifications.drawer"
}
```

## Troubleshooting

#### The `make infra` command failed.

It is possible that you have services running on your machine that occupy either the kafka or postgres ports. To change the default values, open the `local/full-stack-compose.yaml` and change the postgres or kafka or unleash (or all) port bindings:

```diff
diff --git a/local/kafka-compose.yaml b/local/kafka-compose.yaml
Expand Down Expand Up @@ -55,33 +87,4 @@ index f8f3451..60fc9cd 100644

#### The `go run cmd/kafka/testMessage.go`

The command will not work if the main server is not running, or the ws consumer did not start. Ensure you either have feature flags setup or you have bypassed the condition listed in the [step 2](#bypass).


### Chrome frontend

1. ensure you are on the latest version for chrome `master` branch. The support for WS client was added in [#2525](https://github.com/RedHatInsights/insights-chrome/pull/2525).
2. Once your chrome service backend is running, start the chrome dev server with the chrome service config using this command: `CHROME_SERVICE=8000 yarn dev`.
3. The WS client connection is hidden behind a `platform.chrome.notifications-drawer` feature flag. If its not available in your current environment (stage or prod or EE), bypass the feature flag condition in the `src/hooks/useChromeServiceEvents.ts` file.
4. OPen the browser, open the browser console, emit a custom message from the chrome service terminal using `go run cmd/kafka/testMessage.go`.
5. In the network tab of your browser console, filter only to show `ws` communication, click on related ws connection (there will be a couple for webpack dev server, ignore these) and observer the messages being pushed down to the browser.

#### Sample WS message payload

```js
{
// the actual payload consumed by chrome
data: {
description: "Some longer description",
title: "New notification"
},
// cloud events sub protocol metadata
datacontenttype: "application/json",
id: "test-message",
source: "https://whatever.service.com",
specversion: "1.0.2",
time: "2023-05-23T11:54:03.879689005+02:00",
// a type field used to identify message purpose
type: "notifications.drawer"
}
```
The command will not work if the main server is not running, or the ws consumer did not start. Ensure you either have feature flags setup or the pods are running correctly with `podman ps`.
9 changes: 5 additions & 4 deletions src/auth/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { Store } from 'redux';

import * as jwt from '../jwt/jwt';
import { getTokenWithAuthorizationCode } from '../cognito/auth';
import { ITLess } from '../utils/common';
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';
import qe from '../utils/iqeEnablement';
Expand All @@ -20,7 +20,7 @@ export type LibJWT = {
};

const TIMER_STR = '[JWT][jwt.js] Auth time';
const isITLessEnv = ITLess();
const isITLessCognito = ITLessCognito();
function bouncer() {
if (!jwt.isAuthenticated()) {
cookie.remove(defaultOptions.cookieName);
Expand Down Expand Up @@ -48,6 +48,7 @@ export const createAuthObject = (libjwt: LibJWT, getUser: () => Promise<ChromeUs
doOffline: () =>
libjwt.jwt.doOffline(consts.noAuthParam, consts.offlineToken, globalConfig?.chrome?.ssoUrl || globalConfig?.chrome?.config?.ssoUrl),
getToken: () => libjwt.initPromise.then(() => libjwt.jwt.getUserInfo().then(() => libjwt.jwt.getEncodedToken())),
getRefreshToken: () => libjwt.jwt.getRefreshToken(),
getUser,
qe: {
...qe,
Expand All @@ -67,7 +68,7 @@ export const createGetUser = (libjwt: LibJWT): (() => Promise<ChromeUser | undef
export const createGetUserPermissions = (libJwt: LibJWT, getUser: () => Promise<void | ChromeUser>) => {
const fetchPermissions = createFetchPermissionsWatcher(getUser);
return async (app = '', bypassCache?: boolean) => {
if (isITLessEnv) {
if (isITLessCognito) {
const cogToken = await getTokenWithAuthorizationCode();
return fetchPermissions(cogToken || '', app, bypassCache);
} else {
Expand Down Expand Up @@ -98,7 +99,7 @@ export default ({ ssoUrl, ssoScopes }: { ssoUrl?: string; ssoScopes: string[] })
const promise = jwt.init(options, ssoUrl).then(bouncer);

return {
getOfflineToken: () => (isITLessEnv ? getTokenWithAuthorizationCode() : getOfflineToken(options.realm, options.clientId, ssoUrl)),
getOfflineToken: () => (isITLessCognito ? getTokenWithAuthorizationCode() : getOfflineToken(options.realm, options.clientId, ssoUrl)),
jwt: jwt,
initPromise: promise,
};
Expand Down
4 changes: 2 additions & 2 deletions src/bootstrap.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import { ACTIVE_REMOTE_REQUEST, CROSS_ACCESS_ACCOUNT_NUMBER } from './utils/cons
import auth, { LibJWT, createGetUserPermissions, crossAccountBouncer } from './auth';
import sentry from './utils/sentry';
import registerAnalyticsObserver from './analytics/analyticsObserver';
import { ITLess, generateRoutesList, getEnv, loadFedModules, noop, trustarcScriptSetup } from './utils/common';
import { ITLess, ITLessCognito, generateRoutesList, getEnv, loadFedModules, noop, trustarcScriptSetup } from './utils/common';
import messages from './locales/data.json';
import ErrorBoundary from './components/ErrorComponents/ErrorBoundary';
import LibtJWTContext from './components/LibJWTContext';
Expand Down Expand Up @@ -135,7 +135,7 @@ const App = () => {
document.title = `${title}console.redhat.com`;
}, [documentTitle]);

if (isITLessEnv) {
if (ITLessCognito()) {
return isReady && modules && scalprumConfig ? (
<RootApp cookieElement={cookieElement} setCookieElement={setCookieElement} config={scalprumConfig} />
) : (
Expand Down
7 changes: 4 additions & 3 deletions src/chrome/create-chrome.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import {
toggleFeedbackModal,
toggleGlobalFilter,
} from '../redux/actions';
import { ITLess, getEnv, getEnvDetails, isBeta, isProd, updateDocumentTitle } from '../utils/common';
import { ITLess, ITLessCognito, getEnv, getEnvDetails, isBeta, isProd, updateDocumentTitle } from '../utils/common';
import { createSupportCase } from '../utils/createCase';
import debugFunctions from '../utils/debugFunctions';
import { flatTags } from '../components/GlobalFilter/globalFilterApi';
Expand Down Expand Up @@ -99,10 +99,11 @@ export const createChromeContext = ({
};

const isITLessEnv = ITLess();
const isITLessCognito = ITLessCognito();

const api: ChromeAPI = {
...actions,
auth: isITLessEnv ? createCognitoAuthObject(store) : createAuthObject(libJwt, getUser, store, modulesConfig),
auth: isITLessCognito ? createCognitoAuthObject(store) : createAuthObject(libJwt, getUser, store, modulesConfig),
initialized: true,
isProd,
forceDemo: () => Cookies.set('cs_demo', 'true'),
Expand All @@ -113,7 +114,7 @@ export const createChromeContext = ({
getEnvironmentDetails: () => getEnvDetails(),
createCase: (fields?: any) => getUser().then((user) => createSupportCase(user!.identity, libJwt, fields)),
getUserPermissions: async (app = '', bypassCache?: boolean) => {
if (isITLessEnv) {
if (isITLessCognito) {
const cogToken = await getTokenWithAuthorizationCode();
return fetchPermissions(cogToken || '', app, bypassCache);
} else {
Expand Down
2 changes: 2 additions & 0 deletions src/cognito/auth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ export async function getTokenWithAuthorizationCode() {

const redirectUri = dataConfig?.redirectUri;
if (!code && !refreshToken) {
localStorage.clear();
window.location.href = loginUrl;
}
if (refreshToken) {
Expand All @@ -68,6 +69,7 @@ export async function getTokenWithAuthorizationCode() {
body: `grant_type=refresh_token&client_id=${dataConfig?.ClientId}&refresh_token=${localStorage.getItem('REFRESH_TOKEN')}`,
});
if (!response.ok) {
localStorage.clear();
window.location.href = loginUrl;
throw new Error(`Request failed with status code ${response.status}`);
}
Expand Down
2 changes: 0 additions & 2 deletions src/components/AppFilter/useAppFilter.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -368,13 +368,11 @@ describe('useAppFilter', () => {
appId: 'foo',
href: '/openshift/subscriptions/foo',
title: 'subs-nested-ins',
isFedramp: false,
},
{
appId: 'foo',
href: '/insights/subscriptions/foo',
title: 'subs-nested-o',
isFedramp: false,
},
],
title: 'Subscriptions',
Expand Down
12 changes: 3 additions & 9 deletions src/components/AppFilter/useAppFilter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,8 @@ import { useEffect, useState } from 'react';
import { useSelector } from 'react-redux';
import { BundleNavigation, ChromeModule, NavItem } from '../../@types/types';
import { ReduxState } from '../../redux/store';
import { ITLess, getChromeStaticPathname, isBeta, isProd } from '../../utils/common';
import { getChromeStaticPathname, isBeta, isProd } from '../../utils/common';
import { evaluateVisibility } from '../../utils/isNavItemVisible';
import { computeFedrampResult } from '../../utils/useRenderFedramp';

export type AppFilterBucket = {
id: string;
Expand All @@ -27,6 +26,8 @@ export const requiredBundles = [
...(!isProd() ? previewBundles : isBeta() ? previewBundles : []),
];

export const itLessBundles = ['openshift', 'insights', 'settings', 'iam'];

const bundlesOrder = [
'application-services',
'openshift',
Expand All @@ -41,8 +42,6 @@ const bundlesOrder = [
'business-services',
];

const isITLessEnv = ITLess();

function findModuleByLink(href: string, { modules }: Pick<ChromeModule, 'modules'> = { modules: [] }) {
const routes = (modules || [])
.flatMap(({ routes }) => routes.map((route) => (typeof route === 'string' ? route : route.pathname)))
Expand All @@ -55,7 +54,6 @@ function getBundleLink({ title, isExternal, href, routes, expandable, ...rest }:
const subscriptionsLinks: NavItem[] = [];
let url = href;
let appId = rest.appId!;
let isFedramp = computeFedrampResult(isITLessEnv, url, modules[appId]);
if (expandable) {
routes?.forEach(({ href, title, ...rest }) => {
if (href?.includes('/openshift/cost-management') && rest.filterable !== false) {
Expand All @@ -65,7 +63,6 @@ function getBundleLink({ title, isExternal, href, routes, expandable, ...rest }:
if (rest.filterable !== false && (href?.includes('/insights/subscriptions') || href?.includes('/openshift/subscriptions'))) {
subscriptionsLinks.push({
...rest,
isFedramp: false, // openshift and subs are never visible on fedramp.
href,
title,
});
Expand All @@ -76,14 +73,12 @@ function getBundleLink({ title, isExternal, href, routes, expandable, ...rest }:
const truncatedRoute = href.split('/').slice(0, 3).join('/');
url = isExternal ? href : moduleRoute.length > truncatedRoute.length ? moduleRoute : truncatedRoute;
appId = rest.appId ? rest.appId : appId;
isFedramp = computeFedrampResult(isITLessEnv, url, modules[appId]);
}
});
}

return {
...rest,
isFedramp,
appId,
isExternal,
title,
Expand Down Expand Up @@ -142,7 +137,6 @@ const useAppFilter = () => {
}, [])
.flat()
.map((link) => getBundleLink(link, modules || {}))
.filter(({ isFedramp }) => (isITLessEnv ? !!isFedramp : true))
.filter(({ filterable }) => filterable !== false) || [];
const bundleLinks: NavItem[] = [];
const extraLinks: { cost: NavItem[]; subs: NavItem[] } = {
Expand Down
Loading

0 comments on commit bde9edd

Please sign in to comment.