Skip to content

Commit

Permalink
Merge branch 'master' into readme-service-update
Browse files Browse the repository at this point in the history
  • Loading branch information
Hyperkid123 authored Jun 28, 2024
2 parents 2099bfd + 9b05c69 commit 258dfb0
Show file tree
Hide file tree
Showing 31 changed files with 457 additions and 194 deletions.
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,10 @@ devServer: {
```
3. Run insights-chrome with `npm run dev` or `npm run dev:beta`.
## Local search development
See [local search development documentation](./docs/localSearchDevelopment.md).
## LocalStorage Debugging
There are some localStorage values for you to enable debuging information or enable some values that are in experimental state. If you want to enable them call `const iqe = insights.chrome.enable.iqe()` for instance to enable such service. This function will return callback to disable such feature so calling `iqe()` will remove such item from localStorage.
Expand Down
3 changes: 3 additions & 0 deletions cypress/component/DefaultLayout.cy.js
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,9 @@ describe('<Default layout />', () => {
});
reduxRegistry.register(chromeReducer());
store = reduxRegistry.getStore();
cy.intercept('PUT', 'http://localhost:8080/api/notifications/v1/notifications/drawer/read', {
statusCode: 200,
});
cy.intercept('GET', '/api/featureflags/*', {
toggles: [
{
Expand Down
40 changes: 32 additions & 8 deletions cypress/component/NotificationDrawer/NotificationDrawer.cy.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ const notificationDrawerData: NotificationData[] = [
created: new Date().toString(),
description: 'This is a test notification',
source: 'openshift',
bundle: 'rhel',
},
{
id: '2',
Expand All @@ -21,6 +22,7 @@ const notificationDrawerData: NotificationData[] = [
created: new Date().toString(),
description: 'This is a test notification',
source: 'console',
bundle: 'rhel',
},
{
id: '3',
Expand All @@ -29,6 +31,7 @@ const notificationDrawerData: NotificationData[] = [
created: new Date().toString(),
description: 'This is a test notification',
source: 'console',
bundle: 'rhel',
},
];

Expand Down Expand Up @@ -75,41 +78,62 @@ describe('Notification Drawer', () => {
});
});

it('should mark single notification as read', () => {
it('should mark a single notification as read', () => {
cy.intercept('PUT', 'http://localhost:8080/api/notifications/v1/notifications/drawer/read', {
statusCode: 200,
});
cy.mount(<DrawerLayout />);
cy.get('#populate-notifications').click();
cy.get('#drawer-toggle').click();
cy.get('.pf-m-read').should('have.length', 0);
cy.contains('Notification 1').get('input[type="checkbox"]').first().click();
cy.get('[aria-label="Notification actions dropdown"]').first().click();
cy.get('[role="menuitem"]').contains('Mark as read').first().click();
cy.get('.pf-m-read').should('have.length', 1);
});

it('should mark one notification as unread', () => {
it('should mark a single notification as unread', () => {
cy.intercept('PUT', 'http://localhost:8080/api/notifications/v1/notifications/drawer/read', {
statusCode: 200,
});
cy.mount(<DrawerLayout markAll />);
cy.get('#populate-notifications').click();
cy.get('#drawer-toggle').click();
cy.get('.pf-m-read').should('have.length', 3);
cy.contains('Notification 1').get('input[type="checkbox"]').first().click();
cy.get('.pf-m-read').should('have.length', 2);
cy.get('[aria-label="Notification actions dropdown"]').first().click();
cy.get('[role="menuitem"]').contains('Mark as unread').first().click();
});

it('should mark all notifications as read', () => {
cy.intercept('PUT', 'http://localhost:8080/api/notifications/v1/notifications/drawer/read', {
statusCode: 200,
});
cy.mount(<DrawerLayout />);
cy.get('#populate-notifications').click();
cy.get('#drawer-toggle').click();
cy.get('.pf-m-read').should('have.length', 0);
// select all notifications
cy.get('[aria-label="notifications-bulk-select"]').click();
cy.get('[data-ouia-component-id="notifications-bulk-select-select-all"]').click();
// mark selected as read
cy.get('#notifications-actions-toggle').click();
cy.contains('Mark visible as read').click();
cy.contains('Mark selected as read').click();
cy.get('.pf-m-read').should('have.length', 3);
});

it('should mark all notifications as not read', () => {
it('should mark all notifications as unread', () => {
cy.intercept('PUT', 'http://localhost:8080/api/notifications/v1/notifications/drawer/read', {
statusCode: 200,
});
cy.mount(<DrawerLayout markAll />);
cy.get('#populate-notifications').click();
cy.get('#drawer-toggle').click();
cy.get('.pf-m-read').should('have.length', 3);
// select all notifications
cy.get('[aria-label="notifications-bulk-select"]').click();
cy.get('[data-ouia-component-id="notifications-bulk-select-select-all"]').click();
// mark selected as unread
cy.get('#notifications-actions-toggle').click();
cy.contains('Mark visible as unread').click();
cy.contains('Mark selected as unread').click();
cy.get('.pf-m-read').should('have.length', 0);
});

Expand Down
33 changes: 33 additions & 0 deletions docs/localSearchDevelopment.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# Local search development

You can develop and debug search results (homepage, the "Search for services" field) by running Insights Chrome together with chrome-service-backend.

## Prerequisites

1. Have a go language setup. You can follow the [gmv guide](https://github.com/moovweb/gvm#installing).
2. Have a podman installed. [Getting started guide](https://podman.io/get-started)
3. Have the [chrome-service-backend](https://github.com/RedHatInsights/chrome-service-backend) checkout locally.
4. Make sure you terminal supports the [Makefile](https://makefiletutorial.com/) utility.

## Setting up the development environment

chrome-service-backend is the bridge between kafka and the browser client. It exposes the search-index.json endpoint required for Chrome search to function.

### Run chrome-service-backend first

1. Follow the chrome-service-backend steps for local setup (`make dev-static` or `make dev-static-node` should be enough just to serve the static assets including search index).
2. You can request http://localhost:8000/api/chrome-service/v1/static/stable/stage/search/search-index.json (assuming you have left the default port settings) to test the connection and make sure that the chrome service is serving static assets.

### Generate the local search index

1. Follow the chrome-service-backend instructions to generate the search index as a JSON file (running `make generate-search-index` should be enough).

### Start Insights Chrome frontend

1. Once your chrome service backend is running, start the chrome dev server with the chrome service config using this command: `NAV_CONFIG=8000 yarn dev`.

When all the steps are complete, you should be able to see the search results (https://stage.foo.redhat.com:1337, "Search for services") provided from the locally generated search index. Any subsequent update to search index must be followed with `make generate-search-index` to regenerate the search index file.

### Debug tooling

You can enable additional logging of the search results when typing any prompt by editing [levenshtein-search.ts](../src/utils/levenshtein-search.ts) and setting `debugFlag` to true.
8 changes: 4 additions & 4 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -132,16 +132,16 @@
"@data-driven-forms/react-form-renderer": "^3.22.1",
"@formatjs/cli": "4.8.4",
"@openshift/dynamic-plugin-sdk": "^5.0.1",
"@orama/orama": "^2.0.3",
"@patternfly/patternfly": "^5.3.0",
"@patternfly/quickstarts": "^5.3.0",
"@patternfly/quickstarts": "^5.4.0-prerelease.1",
"@patternfly/react-charts": "^7.3.0",
"@patternfly/react-core": "^5.3.0",
"@patternfly/react-icons": "^5.3.0",
"@patternfly/react-tokens": "^5.3.0",
"@orama/orama": "^2.0.3",
"@redhat-cloud-services/frontend-components": "^4.2.2",
"@redhat-cloud-services/chrome": "^1.0.9",
"@redhat-cloud-services/entitlements-client": "1.2.0",
"@redhat-cloud-services/frontend-components": "^4.2.2",
"@redhat-cloud-services/frontend-components-notifications": "^4.1.0",
"@redhat-cloud-services/frontend-components-pdf-generator": "4.0.4",
"@redhat-cloud-services/frontend-components-utilities": "^4.0.2",
Expand Down
2 changes: 2 additions & 0 deletions src/chrome/create-chrome.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,8 @@ describe('create chrome', () => {
setPageMetadata: jest.fn(),
useGlobalFilter: jest.fn(),
registerModule: jest.fn(),
addNavListener: jest.fn(),
deleteNavListener: jest.fn(),
};
beforeAll(() => {
const mockAuthMethods = {
Expand Down
19 changes: 13 additions & 6 deletions src/chrome/create-chrome.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,12 @@
import { createFetchPermissionsWatcher } from '../auth/fetchPermissions';
import { AppNavigationCB, ChromeAPI, GenericCB, NavDOMEvent } from '@redhat-cloud-services/types';
import { AppNavigationCB, ChromeAPI, GenericCB } from '@redhat-cloud-services/types';
import { Store } from 'redux';
import { AnalyticsBrowser } from '@segment/analytics-next';
import get from 'lodash/get';
import Cookies from 'js-cookie';

import {
AppNavClickItem,
appAction,
appNavClick,
appObjectId,
globalFilterScope,
removeGlobalFilter,
Expand Down Expand Up @@ -37,6 +35,7 @@ import requestPdf from '../pdf/requestPdf';
import chromeStore from '../state/chromeStore';
import { isFeedbackModalOpenAtom } from '../state/atoms/feedbackModalAtom';
import { usePendoFeedback } from '../components/Feedback';
import { NavListener, activeAppAtom } from '../state/atoms/activeAppAtom';

export type CreateChromeContextConfig = {
useGlobalFilter: (callback: (selectedTags?: FlagTagsFilter) => any) => ReturnType<typeof callback>;
Expand All @@ -48,6 +47,8 @@ export type CreateChromeContextConfig = {
chromeAuth: ChromeAuthContextValue;
registerModule: (payload: RegisterModulePayload) => void;
isPreview: boolean;
addNavListener: (cb: NavListener) => number;
deleteNavListener: (id: number) => void;
};

export const createChromeContext = ({
Expand All @@ -60,14 +61,16 @@ export const createChromeContext = ({
registerModule,
chromeAuth,
isPreview,
addNavListener,
deleteNavListener,
}: CreateChromeContextConfig): ChromeAPI => {
const fetchPermissions = createFetchPermissionsWatcher(chromeAuth.getUser);
const visibilityFunctions = getVisibilityFunctions();
const dispatch = store.dispatch;
const actions = {
appAction: (action: string) => dispatch(appAction(action)),
appObjectId: (objectId: string) => dispatch(appObjectId(objectId)),
appNavClick: (item: AppNavClickItem, event?: NavDOMEvent) => dispatch(appNavClick(item, event)),
appNavClick: (item: string) => chromeStore.set(activeAppAtom, item),
globalFilterScope: (scope: string) => dispatch(globalFilterScope(scope)),
registerModule: (module: string, manifest?: string) => registerModule({ module, manifest }),
removeGlobalFilter: (isHidden: boolean) => {
Expand All @@ -76,13 +79,17 @@ export const createChromeContext = ({
},
};

const on = (type: keyof typeof PUBLIC_EVENTS, callback: AppNavigationCB | GenericCB) => {
const on = (type: keyof typeof PUBLIC_EVENTS | 'APP_NAVIGATION', callback: AppNavigationCB | GenericCB) => {
if (type === 'APP_NAVIGATION') {
const listenerId = addNavListener(callback);
return () => deleteNavListener(listenerId);
}
if (!Object.prototype.hasOwnProperty.call(PUBLIC_EVENTS, type)) {
throw new Error(`Unknown event type: ${type}`);
}

const [listener, selector] = PUBLIC_EVENTS[type];
if (type !== 'APP_NAVIGATION' && typeof selector === 'string') {
if (typeof selector === 'string') {
(callback as GenericCB)({
data: get(store.getState(), selector) || {},
});
Expand Down
81 changes: 0 additions & 81 deletions src/components/ChromeLink/ChromeLink.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import createMockStore from 'redux-mock-store';
import { MemoryRouter } from 'react-router-dom';
import ChromeLink from './ChromeLink';
import NavContext from '../Navigation/navContext';
import { APP_NAV_CLICK } from '../../redux/action-types';

const LinkContext = ({
store,
Expand Down Expand Up @@ -48,86 +47,6 @@ describe('ChromeLink', () => {
expect(getAllByTestId('router-link')).toHaveLength(1);
});

test('should dispatch appNavClick with correct actionId for top level route', () => {
const store = mockStore({
chrome: {
moduleRoutes: [],
activeModule: 'testModule',
modules: {
testModule: {},
},
},
});
const {
container: { firstElementChild: buttton },
} = render(
<LinkContext store={store}>
<ChromeLink {...testProps}>Test module link</ChromeLink>
</LinkContext>
);

act(() => {
fireEvent.click(buttton);
});

expect(store.getActions()).toEqual([
{
type: APP_NAV_CLICK,
payload: {
id: '/',
event: {
id: '/',
navId: '/',
href: '/insights/foo',
type: 'click',
target: expect.any(Element),
},
},
},
]);
});

test('should dispatch appNavClick with correct actionId for nested route', () => {
const store = mockStore({
chrome: {
moduleRoutes: [],
activeModule: 'testModule',
modules: {
testModule: {},
},
},
});
const {
container: { firstElementChild: buttton },
} = render(
<LinkContext store={store}>
<ChromeLink {...testProps} href="/insights/foo/bar">
Test module link
</ChromeLink>
</LinkContext>
);

act(() => {
fireEvent.click(buttton);
});

expect(store.getActions()).toEqual([
{
type: APP_NAV_CLICK,
payload: {
id: 'bar',
event: {
id: 'bar',
navId: 'bar',
href: '/insights/foo/bar',
type: 'click',
target: expect.any(Element),
},
},
},
]);
});

test('should not trigger onLinkClick callback', () => {
const onLinkClickSpy = jest.fn();
const store = mockStore({
Expand Down
Loading

0 comments on commit 258dfb0

Please sign in to comment.