Skip to content

Commit

Permalink
PR comments
Browse files Browse the repository at this point in the history
  • Loading branch information
christineweng committed Dec 5, 2024
1 parent cf2afcf commit e19c913
Show file tree
Hide file tree
Showing 13 changed files with 206 additions and 184 deletions.
2 changes: 2 additions & 0 deletions packages/kbn-expandable-flyout/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,8 @@ To control (or mutate) flyout's layout, you can utilize [useExpandableFlyoutApi]

> The expandable flyout propagates the `onClose` callback from the EuiFlyout component. As we recommend having a single instance of the flyout in your application, it's up to the application's code to dispatch the event (through Redux, window events, observable, prop drilling...).
When calling `openFlyout`, the right panel state is automatically appended in the `history` slice in the redux context. To access the flyout's history, you can use the [useExpandableFlyoutHistory](https://github.com/elastic/kibana/blob/main/packages/kbn-expandable-flyout/src/hooks/use_expandable_flyout_history.ts) hook.

## Usage

To use the expandable flyout in your plugin, first you need wrap your code with the [context provider](https://github.com/elastic/kibana/blob/main/packages/kbn-expandable-flyout/src/context.tsx) at a high enough level as follows:
Expand Down
2 changes: 1 addition & 1 deletion packages/kbn-expandable-flyout/src/store/state.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ export interface FlyoutPanels {
*/
preview: FlyoutPanelProps[] | undefined;
/*
* History of the right panel that were opened
* History of the right panels that were opened
*/
history: FlyoutPanelProps[];
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,25 +48,3 @@ export const getEcsAllowedValueDescription = (fieldName: FieldName, value: strin
})
);
};

// mapping of event category to the field displayed as title
export const EVENT_CATEGORY_TO_FIELD: Record<string, string> = {
authentication: 'user.name',
configuration: '',
database: '',
driver: '',
email: '',
file: 'file.name',
host: 'host.name',
iam: '',
intrusion_detection: '',
malware: '',
network: '',
package: '',
process: 'process.name',
registry: '',
session: '',
threat: '',
vulnerability: '',
web: '',
};
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
*/
import { getField, getFieldArray, getEventTitle, getAlertTitle } from './utils';

describe('test getField', () => {
describe('getField', () => {
it('should return the string value if field is a string', () => {
expect(getField('test string')).toBe('test string');
});
Expand All @@ -29,7 +29,7 @@ describe('test getField', () => {
});
});

describe('test getFieldArray', () => {
describe('getFieldArray', () => {
it('should return the string value in an array if field is a string', () => {
expect(getFieldArray('test string')).toStrictEqual(['test string']);
});
Expand All @@ -48,8 +48,8 @@ describe('test getFieldArray', () => {
});
});

describe('test getEventTitle', () => {
it('when event kind is event, return event title based on category', () => {
describe('getEventTitle', () => {
it('should return event title based on category when event kind is event', () => {
expect(
getEventTitle({
eventKind: 'event',
Expand All @@ -59,31 +59,31 @@ describe('test getEventTitle', () => {
).toBe('process name');
});

it('when event kind is alert, return External alert details', () => {
it('should return External alert details when event kind is alert', () => {
expect(
getEventTitle({ eventKind: 'alert', eventCategory: null, getFieldsData: jest.fn() })
).toBe('External alert details');
});

it('when event kind is not event or alert, return Event kind details', () => {
it('should return generic event details when event kind is not event or alert', () => {
expect(
getEventTitle({ eventKind: 'metric', eventCategory: null, getFieldsData: jest.fn() })
).toBe('Metric details');
});

it('when event kind is null, return Event details', () => {
it('should return Event details when event kind is null', () => {
expect(getEventTitle({ eventKind: null, eventCategory: null, getFieldsData: jest.fn() })).toBe(
'Event details'
);
});
});

describe('test getAlertTitle', () => {
it('when ruleName is undefined, return Document details', () => {
describe('getAlertTitle', () => {
it('should return Document details when ruleName is undefined', () => {
expect(getAlertTitle({ ruleName: undefined })).toBe('Document details');
});

it('when ruleName is defined, return ruleName', () => {
it('should return ruleName when ruleName is defined', () => {
expect(getAlertTitle({ ruleName: 'test rule' })).toBe('test rule');
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
*/
import { i18n } from '@kbn/i18n';
import { startCase } from 'lodash';
import { EVENT_CATEGORY_TO_FIELD } from '../right/utils/event_utils';
import type { GetFieldsData } from './hooks/use_get_fields_data';

/**
Expand Down Expand Up @@ -38,14 +37,42 @@ export const getFieldArray = (field: unknown | unknown[]) => {
return [];
};

export const getAlertTitle = ({ ruleName }: { ruleName: string | undefined }) => {
// mapping of event category to the field displayed as title
export const EVENT_CATEGORY_TO_FIELD: Record<string, string> = {
authentication: 'user.name',
configuration: '',
database: '',
driver: '',
email: '',
file: 'file.name',
host: 'host.name',
iam: '',
intrusion_detection: '',
malware: '',
network: '',
package: '',
process: 'process.name',
registry: '',
session: '',
threat: '',
vulnerability: '',
web: '',
};

/**
* Helper function to retrieve the alert title
*/
export const getAlertTitle = ({ ruleName }: { ruleName?: string | null }) => {
const defaultAlertTitle = i18n.translate(
'xpack.securitySolution.flyout.right.header.headerTitle',
{ defaultMessage: 'Document details' }
);
return ruleName ?? defaultAlertTitle;
};

/**
* Helper function to retrieve the event title
*/
export const getEventTitle = ({
eventKind,
eventCategory,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import {
FLYOUT_HISTORY_BUTTON_TEST_ID,
FLYOUT_HISTORY_CONTEXT_PANEL_TEST_ID,
} from './test_ids';
import { FlyoutHistory, getProcessedHistory } from './flyout_history';
import { FlyoutHistory } from './flyout_history';

const mockedHistory = [{ id: '1' }, { id: '2' }];

Expand Down Expand Up @@ -48,51 +48,3 @@ describe('FlyoutHistory', () => {
expect(container).toBeEmptyDOMElement();
});
});

describe('getProcessedHistory', () => {
const simpleHistory = [{ id: '1' }, { id: '2' }, { id: '3' }, { id: '4' }];
const complexHistory = [
{ id: '1' },
{ id: '2' },
{ id: '1' },
{ id: '3' },
{ id: '4' },
{ id: '2' },
];

it('returns a reversed history array and removes latest entry', () => {
// input: 1, 2, 3, 4
// reverse: 4, 3, 2, 1
// remove latest: 4, 3, 2
const processedHistory = getProcessedHistory({ history: simpleHistory, maxCount: 5 });
expect(processedHistory).toEqual([{ id: '3' }, { id: '2' }, { id: '1' }]);
});

it('returns processed history with the maxCount', () => {
// input: 1, 2, 3, 4
// reverse: 4, 3, 2, 1
// remove latest: 3, 2, 1
// keep maxCount: 3, 2
const processedHistory = getProcessedHistory({ history: simpleHistory, maxCount: 2 });
expect(processedHistory).toEqual([{ id: '3' }, { id: '2' }]);
});

it('removes duplicates and reverses', () => {
// input: 1, 2, 1, 3, 4, 2
// reverse: 2, 4, 3, 1, 2, 1
// remove duplicates: 2, 4, 3, 1
// remove latest: 4, 3, 1
const processedHistory = getProcessedHistory({ history: complexHistory, maxCount: 5 });
expect(processedHistory).toEqual([{ id: '4' }, { id: '3' }, { id: '1' }]);
});

it('returns empty array if history only has one entry', () => {
const processedHistory = getProcessedHistory({ history: [{ id: '1' }], maxCount: 5 });
expect(processedHistory).toEqual([]);
});

it('returns empty array if history is empty', () => {
const processedHistory = getProcessedHistory({ history: [], maxCount: 5 });
expect(processedHistory).toEqual([]);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,6 @@ export interface HistoryProps {
* A list of flyouts that have been opened
*/
history: FlyoutPanelProps[];
/**
* Maximum number of flyouts to show in history
*/
maxCount?: number;
}

/**
Expand Down Expand Up @@ -74,27 +70,3 @@ export const FlyoutHistory: FC<HistoryProps> = memo(({ history }) => {
});

FlyoutHistory.displayName = 'FlyoutHistory';

/**
* Helper function that reverses the history array,
* removes duplicates and the most recent item
* @returns a history array of maxCount length
*/
export const getProcessedHistory = ({
history,
maxCount,
}: {
history: FlyoutPanelProps[];
maxCount: number;
}): FlyoutPanelProps[] => {
// Step 1: reverse history so the most recent is first
const reversedHistory = history.slice().reverse();

// Step 2: remove duplicates
const historyArray = Array.from(new Set(reversedHistory.map((i) => JSON.stringify(i)))).map((i) =>
JSON.parse(i)
);

// Omit the first (current) entry and return array of maxCount length
return historyArray.slice(1, maxCount + 1);
};
Loading

0 comments on commit e19c913

Please sign in to comment.