Skip to content

Commit

Permalink
feat(config-utils): enable minor config files proxy interception
Browse files Browse the repository at this point in the history
enables search index and services tiles config interception
  • Loading branch information
Hyperkid123 committed Jan 20, 2025
1 parent 002f2d9 commit 49b7aed
Show file tree
Hide file tree
Showing 6 changed files with 130 additions and 44 deletions.
13 changes: 13 additions & 0 deletions packages/config-utils/src/feo/check-outgoing-requests.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,16 @@
export function matchNavigationRequest(url: string): boolean {
return !!url.match(/\/api\/chrome-service\/v1\/static\/bundles-generated\.json/);
}

export function matchSearchIndexRequest(url: string): boolean {
return !!url.match(/\/api\/chrome-service\/v1\/static\/search-index-generated\.json/);
}

export function matchServiceTilesRequest(url: string): boolean {
return !!url.match(/\/api\/chrome-service\/v1\/static\/service-tiles-generated\.json/);
}

export function isInterceptAbleRequest(url: string): boolean {
const checks = [matchNavigationRequest, matchSearchIndexRequest, matchServiceTilesRequest];
return checks.some((check) => check(url));
}
24 changes: 14 additions & 10 deletions packages/config-utils/src/feo/feo-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -107,16 +107,6 @@ export type ServiceTile = {
frontendRef: string;
};

export type ServiceGroup = {
id: string;
tiles: ServiceTile[];
};

export type ServiceCategory = {
id: string;
groups: ServiceGroup[];
};

export type ChromeWidgetEntry = {
scope: string;
module: string;
Expand All @@ -141,3 +131,17 @@ export type CRDObject = {
export type FrontendCRD = {
objects: CRDObject[];
};

export type ServicesTilesGroupResponseEntry = {
id: string;
isGroup?: boolean;
title: string;
links: ServiceTile[];
};

export type ServicesTilesResponseEntry = {
description: string;
icon: string;
id: string;
links: ServicesTilesGroupResponseEntry[];
};
49 changes: 49 additions & 0 deletions packages/config-utils/src/feo/modify-response.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import { matchNavigationRequest, matchSearchIndexRequest, matchServiceTilesRequest } from './check-outgoing-requests';
import { ChromeStaticSearchEntry, FrontendCRD, GeneratedBundles, ServicesTilesResponseEntry } from './feo-types';
import navigationInterceptor from './navigation-interceptor';
import searchInterceptor from './search-interceptor';
import serviceTilesInterceptor from './service-tiles-interceptor';

function isGeneratedBundles(
body: GeneratedBundles | ChromeStaticSearchEntry[] | ServicesTilesResponseEntry[],
url: string
): body is GeneratedBundles {
return matchNavigationRequest(url);
}

function isSearchIndex(
body: GeneratedBundles | ChromeStaticSearchEntry[] | ServicesTilesResponseEntry[],
url: string
): body is ChromeStaticSearchEntry[] {
return matchSearchIndexRequest(url);
}

function isServiceTiles(
body: GeneratedBundles | ChromeStaticSearchEntry[] | ServicesTilesResponseEntry[],
url: string
): body is ServicesTilesResponseEntry[] {
return matchServiceTilesRequest(url);
}

export function modifyRequest(body: string, url: string, frontendCrd: FrontendCRD): string {
const objectToModify = JSON.parse(body);
// return original if no match is found
let payload: string = body;
if (isGeneratedBundles(objectToModify, url)) {
const resultBundles: GeneratedBundles = [];
objectToModify.forEach((bundle) => {
const navItems = navigationInterceptor(frontendCrd, bundle, bundle.id);
resultBundles.push({ ...bundle, navItems });
});
payload = JSON.stringify(resultBundles);
} else if (isSearchIndex(objectToModify, url)) {
const staticSearch = objectToModify as ChromeStaticSearchEntry[];
const result = searchInterceptor(staticSearch, frontendCrd);
payload = JSON.stringify(result);
} else if (isServiceTiles(objectToModify, url)) {
const staticServicesTiles = objectToModify as ServicesTilesResponseEntry[];
const result = serviceTilesInterceptor(staticServicesTiles, frontendCrd);
payload = JSON.stringify(result);
}
return payload;
}
38 changes: 25 additions & 13 deletions packages/config-utils/src/feo/service-tiles-interceptor.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { FrontendCRD, ServiceCategory } from './feo-types';
import { FrontendCRD, ServicesTilesResponseEntry } from './feo-types';
import serviceTilesInterceptor from './service-tiles-interceptor';

describe('Service tiles interceptor', () => {
Expand Down Expand Up @@ -38,13 +38,16 @@ describe('Service tiles interceptor', () => {
},
],
};
const remoteServiceTiles: ServiceCategory[] = [
const remoteServiceTiles: ServicesTilesResponseEntry[] = [
{
id: 'section-1',
groups: [
description: 'section 1',
icon: 'icon',
links: [
{
id: 'group-1',
tiles: [
title: 'Group 1',
links: [
{
section: 'section-1',
group: 'group-1',
Expand All @@ -63,10 +66,13 @@ describe('Service tiles interceptor', () => {
},
{
id: 'section-2',
groups: [
description: 'section 2',
icon: 'icon',
links: [
{
id: 'group-1',
tiles: [
title: 'Group 1',
links: [
{
section: 'section-2',
group: 'group-1',
Expand All @@ -78,14 +84,17 @@ describe('Service tiles interceptor', () => {
],
},
];
const expectedServiceTiles: ServiceCategory[] = [
const expectedServiceTiles: ServicesTilesResponseEntry[] = [
{
id: 'section-1',
groups: [
description: 'section 1',
icon: 'icon',
links: [
{
title: 'Group 1',
id: 'group-1',
tiles: [
remoteServiceTiles[0].groups[0].tiles[0],
links: [
remoteServiceTiles[0].links[0].links[0],
{
section: 'section-1',
group: 'group-1',
Expand All @@ -104,11 +113,14 @@ describe('Service tiles interceptor', () => {
},
{
id: 'section-2',
groups: [
description: 'section 2',
icon: 'icon',
links: [
{
title: 'Group 1',
id: 'group-1',
tiles: [
remoteServiceTiles[1].groups[0].tiles[0],
links: [
remoteServiceTiles[1].links[0].links[0],
{
section: 'section-2',
group: 'group-1',
Expand Down
12 changes: 6 additions & 6 deletions packages/config-utils/src/feo/service-tiles-interceptor.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { FrontendCRD, ServiceCategory, ServiceTile } from './feo-types';
import { FrontendCRD, ServiceTile, ServicesTilesResponseEntry } from './feo-types';

function serviceTilesInterceptor(serviceCategories: ServiceCategory[], frontendCrd: FrontendCRD): ServiceCategory[] {
function serviceTilesInterceptor(serviceCategories: ServicesTilesResponseEntry[], frontendCrd: FrontendCRD): ServicesTilesResponseEntry[] {
const frontendRef = frontendCrd.objects[0].metadata.name;
let result = [...serviceCategories];

Expand All @@ -23,16 +23,16 @@ function serviceTilesInterceptor(serviceCategories: ServiceCategory[], frontendC
}, {}) ?? {};

result = result.map((category) => {
const newGroups = category.groups.map((group) => {
const newTiles = group.tiles.filter((tile) => tile.frontendRef !== frontendRef);
const newGroups = category.links.map((group) => {
const newTiles = group.links.filter((tile) => tile.frontendRef !== frontendRef);
return {
...group,
tiles: [...newTiles, ...(frontendCategories[category.id]?.[group.id] ?? [])],
links: [...newTiles, ...(frontendCategories[category.id]?.[group.id] ?? [])],
};
});
return {
...category,
groups: newGroups,
links: newGroups,
};
});

Expand Down
38 changes: 23 additions & 15 deletions packages/config-utils/src/proxy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,12 @@ import path from 'path';
import type { Configuration } from 'webpack-dev-server';
import { HttpsProxyAgent } from 'https-proxy-agent';
import cookieTransform from './cookieTransform';
import { matchNavigationRequest } from './feo/check-outgoing-requests';
import { isInterceptAbleRequest, matchNavigationRequest } from './feo/check-outgoing-requests';
import { hasFEOFeaturesEnabled, readFrontendCRD } from './feo/crd-check';
import navigationInterceptor from './feo/navigation-interceptor';
import { GeneratedBundles } from './feo/feo-types';
import { FrontendCRD, GeneratedBundles } from './feo/feo-types';
import { modifyRequest } from './feo/modify-response';
import { LogType, fecLogger } from '.';

const defaultReposDir = path.join(__dirname, 'repos');

Expand Down Expand Up @@ -136,8 +138,17 @@ const proxy = ({
// will be used once the interceptor is ready
frontendCRDPath = path.resolve(process.cwd(), 'deploy/frontend.yaml'),
}: ProxyOptions) => {
const frontendCrd = readFrontendCRD(frontendCRDPath);
const FEOFeaturesEnabled = hasFEOFeaturesEnabled(frontendCrd);
let frontendCrd: FrontendCRD;
let FEOFeaturesEnabled = false;
try {
frontendCrd = readFrontendCRD(frontendCRDPath);
FEOFeaturesEnabled = hasFEOFeaturesEnabled(frontendCrd);
} catch (e) {
fecLogger(
LogType.warn,
`FEO features are not enabled. Unable to find frontend CRD file at ${frontendCRDPath}. If you want FEO features for local development, make sure to have a "deploy/frontend.yaml" file in your project or specify its location via "frontendCRDPath" attribute.`
);
}
const proxy: ProxyConfigItem[] = [];
const majorEnv = env.split('-')[0];
const defaultLocalAppHost = process.env.LOCAL_APP_HOST || majorEnv + '.foo.redhat.com';
Expand Down Expand Up @@ -204,7 +215,7 @@ const proxy = ({
changeOrigin: true,
autoRewrite: true,
onProxyReq: (proxyReq, req) => {
if (matchNavigationRequest(req.url)) {
if (isInterceptAbleRequest(req.url)) {
// necessary to avoid gzip encoding and issues with parsing the json body
proxyReq.setHeader('accept-encoding', 'gzip;q=0,deflate,sdch');
}
Expand All @@ -213,7 +224,7 @@ const proxy = ({
// this should reading the aggregated bundles filed generated from chrome service
// The functionality is disabled until the interceptor is ready
// eslint-disable-next-line no-constant-condition
if (matchNavigationRequest(req.url)) {
if (isInterceptAbleRequest(req.url)) {
// stub the original write function
const _write = res.write;
let body = '';
Expand All @@ -223,17 +234,14 @@ const proxy = ({

res.write = function () {
try {
const objectToModify = JSON.parse(body) as GeneratedBundles;
const resultBundles: GeneratedBundles = [];
if (FEOFeaturesEnabled) {
// these will be filled in chrome service once migration is ready to start
objectToModify.forEach((bundle) => {
const navItems = navigationInterceptor(frontendCrd, bundle, bundle.id);
resultBundles.push({ ...bundle, navItems });
});
const payload = modifyRequest(body, req.url, frontendCrd);
// content length is necessary to update to prevent JSON parsing errors in browser
res.setHeader('content-length', payload.length);
_write.call(res, payload, 'utf8');
} else {
_write.call(res, body, 'utf8');
}
const payload = JSON.stringify(resultBundles);
_write.call(res, payload, 'utf8');
return true;
} catch {
// wait for all the chunks to arrive
Expand Down

0 comments on commit 49b7aed

Please sign in to comment.