Skip to content

Commit

Permalink
[Security Solution] Add ComparisonSide component (#189384)
Browse files Browse the repository at this point in the history
**Partially addresses: #171520

## Summary

This PR adds the `ComparisonSide` component for the ThreeWayDiff UI
([see it on the Miro
diagram](https://miro.com/app/board/uXjVK0gqjjQ=/?moveToWidget=3458764594147853908&cot=14)).

`ComparisonSide` lets the user compare field values from the two
selected rule versions. It will be displayed on the left side of the
upgrade flyout.

You can view and test it in Storybook by running `yarn storybook
security_solution` in the root Kibana dir. Go to `http://localhost:9001`
once the Storybook is up and running.


https://github.com/user-attachments/assets/e71ae626-d0f7-43ae-8324-f3d4ea540b02


Also updated `react-diff-view` to the latest version (`3.2.0` ->
`3.2.1`)
  • Loading branch information
nikitaindik committed Aug 8, 2024
1 parent b87e967 commit 3de37ce
Show file tree
Hide file tree
Showing 27 changed files with 1,315 additions and 20 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -1150,7 +1150,7 @@
"re2js": "0.4.1",
"react": "^17.0.2",
"react-ace": "^7.0.5",
"react-diff-view": "^3.2.0",
"react-diff-view": "^3.2.1",
"react-dom": "^17.0.2",
"react-dropzone": "^4.2.9",
"react-fast-compare": "^2.0.4",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import type {
HunkTokens,
} from 'react-diff-view';
import unidiff from 'unidiff';
import type { Change } from 'diff';
import { useEuiTheme, COLOR_MODES_STANDARD } from '@elastic/eui';
import { Hunks } from './hunks';
import { markEdits, DiffMethod } from './mark_edits';
Expand Down Expand Up @@ -111,15 +112,32 @@ const renderGutter: RenderGutter = ({ change }) => {
return null;
};

/**
* Converts an array of Change objects into a "unified diff" string.
*
* Takes an array of changes (as provided by the jsdiff library) and converts it into a "unified diff" string.
*
* @param {Change[]} changes - An array of changes between two strings.
* @returns {string} A unified diff string representing the changes.
*/
const convertChangesToUnifiedDiffString = (changes: Change[]): string => {
const unifiedDiff: string = unidiff.formatLines(changes, {
context: 3,
});

return unifiedDiff;
};

const convertToDiffFile = (oldSource: string, newSource: string) => {
/*
"diffLines" call converts two strings of text into an array of Change objects.
*/
const changes = unidiff.diffLines(oldSource, newSource);
const changes: Change[] = unidiff.diffLines(oldSource, newSource);

/*
Then "formatLines" takes an array of Change objects and turns it into a single "unified diff" string.
More info about the "unified diff" format: https://en.wikipedia.org/wiki/Diff_utility#Unified_format
"convertChangesToUnifiedDiffString" converts an array of Change objects into a single "unified diff" string.
More info about the "unified diff" format: https://en.wikipedia.org/wiki/Diff#Unified_format
Unified diff is a string with change markers added. Looks something like:
`
@@ -3,16 +3,15 @@
Expand All @@ -129,9 +147,7 @@ const convertToDiffFile = (oldSource: string, newSource: string) => {
"history_window_start": "now-14d",
`
*/
const unifiedDiff: string = unidiff.formatLines(changes, {
context: 3,
});
const unifiedDiff: string = convertChangesToUnifiedDiffString(changes);

/*
"parseDiff" converts a unified diff string into a gitdiff-parser File object.
Expand All @@ -154,18 +170,34 @@ const CustomStyles: FC<PropsWithChildren<unknown>> = ({ children }) => {
padding: 0 ${euiTheme.size.l} 0 ${euiTheme.size.m};
}
/* Gutter - a narrow column on the left-hand side that displays either a "+" or a "-" */
.${TABLE_CLASS_NAME} .diff-gutter-col {
width: ${euiTheme.size.xl};
}
/*
Hide the redundant second gutter column in "unified" view.
Hiding it with "display: none" would break the layout, so we set its width to 0 and make its content invisible.
*/
.${TABLE_CLASS_NAME}.diff-unified .diff-gutter-col + .diff-gutter-col {
width: 0;
}
.${TABLE_CLASS_NAME}.diff-unified .diff-gutter + .diff-gutter {
visibility: hidden;
}
/* Vertical line separating two sides of the diff view */
.${GUTTER_CLASS_NAME}:nth-child(3) {
border-left: 1px solid ${euiTheme.colors.mediumShade};
}
.${GUTTER_CLASS_NAME}.diff-gutter-delete, .${GUTTER_CLASS_NAME}.diff-gutter-insert {
font-weight: bold;
text-align: center;
}
/* Gutter of a line with deletions */
.${GUTTER_CLASS_NAME}.diff-gutter-delete {
font-weight: bold;
background: ${COLORS.light.gutterBackground.deletion};
}
.${DARK_THEME_CLASS_NAME} .${GUTTER_CLASS_NAME}.diff-gutter-delete {
Expand All @@ -174,7 +206,6 @@ const CustomStyles: FC<PropsWithChildren<unknown>> = ({ children }) => {
/* Gutter of a line with insertions */
.${GUTTER_CLASS_NAME}.diff-gutter-insert {
font-weight: bold;
background: ${COLORS.light.gutterBackground.insertion};
}
.${DARK_THEME_CLASS_NAME} .${GUTTER_CLASS_NAME}.diff-gutter-insert {
Expand Down Expand Up @@ -228,12 +259,14 @@ interface DiffViewProps extends Partial<DiffProps> {
oldSource: string;
newSource: string;
diffMethod?: DiffMethod;
viewType?: 'split' | 'unified';
}

export const DiffView = ({
oldSource,
newSource,
diffMethod = DiffMethod.WORDS,
viewType = 'split',
}: DiffViewProps) => {
/*
"react-diff-view" components consume diffs not as a strings, but as something they call "hunks".
Expand Down Expand Up @@ -272,6 +305,7 @@ export const DiffView = ({
Passing 'add' or 'delete' would skip rendering one of the sides in split view.
*/
diffType={diffFile.type}
viewType={viewType}
hunks={hunks}
renderGutter={renderGutter}
tokens={tokens}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,20 @@
* 2.0.
*/

declare module 'unidiff' {
interface Change {
count?: number | undefined;
value: string;
added?: boolean | undefined;
removed?: boolean | undefined;
}
interface Change {
count?: number | undefined;
value: string;
added?: boolean | undefined;
removed?: boolean | undefined;
}

type ADDED = 'ADDED';
type REMOVED = 'REMOVED';
type UNMODIFIED = 'UNMODIFIED';

type LineChangeType = ADDED | REMOVED | UNMODIFIED;

declare module 'unidiff' {
export interface FormatOptions {
context?: number;
}
Expand All @@ -21,3 +27,28 @@ declare module 'unidiff' {

export function formatLines(line: Change[], options?: FormatOptions): string;
}

declare module 'unidiff/hunk' {
export const ADDED: ADDED;
export const REMOVED: REMOVED;
export const UNMODIFIED: UNMODIFIED;

export type ChangeWithType = Change & { type: LineChangeType };

export interface LineChange {
type: LineChangeType;
text: string;
unified(): string;
}

export interface UniDiffHunk {
aoff: number;
boff: number;
changes: LineChange[];
unified(): string;
}

export function lineChanges(change: ChangeWithType): LineChange[];

export function hunk(aOffset: number, bOffset: number, lchanges: LineChange[]): UniDiffHunk;
}
Loading

0 comments on commit 3de37ce

Please sign in to comment.