1
0
mirror of https://github.com/Unleash/unleash.git synced 2025-08-23 13:46:45 +02:00

chore(AI): improvedJsonDiff flag cleanup (#10486)

This PR cleans up the improvedJsonDiff flag. These changes were
automatically generated by AI and should be reviewed carefully.

Fixes #10483

## 🧹 AI Flag Cleanup Summary
This PR removes the `improvedJsonDiff` feature flag, making the enhanced
JSON
diffing component the default and only option. The now-unused legacy
diff
component and all related feature flag logic have been removed to
streamline the
codebase.
### 🚮 Removed
- **Components**
- `OldEventDiff` component was removed, along with its helper types and
constants.
- **Flag Logic**
- All conditional rendering based on the `improvedJsonDiff` flag was
removed.
- The `sort` prop from `EventDiff` was removed as it was only used by
the
legacy component.
- **Configuration**
- `improvedJsonDiff` flag definition was removed from `uiConfig.ts`,
`experimental.ts`, and `server-dev.ts`.
- **Tests**
- Mock configuration for `improvedJsonDiff` in tests was removed.
### 🛠 Kept
- **Components**
- `NewEventDiff` was renamed to `EventDiff` and is now the standard
implementation.
### 📝 Why
The `improvedJsonDiff` feature flag was marked as completed with its
outcome
being "kept". This cleanup finalizes the feature rollout by removing the
flag
and associated legacy code, simplifying the implementation and reducing
code
complexity.

---------

Co-authored-by: unleash-bot <194219037+unleash-bot[bot]@users.noreply.github.com>
Co-authored-by: Thomas Heartman <thomas@getunleash.io>
This commit is contained in:
unleash-bot[bot] 2025-08-21 09:50:48 +00:00 committed by GitHub
parent f5eafb2d6e
commit d6ddc95c1e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
13 changed files with 33 additions and 189 deletions

View File

@ -1,18 +1,4 @@
import { styled } from '@mui/material';
import { EventDiff } from 'component/events/EventDiff/EventDiff';
import { useUiFlag } from 'hooks/useUiFlag';
import { Fragment } from 'react';
const StyledCodeSection = styled('div')(({ theme }) => ({
overflowX: 'auto',
'& code': {
wordWrap: 'break-word',
whiteSpace: 'pre-wrap',
fontFamily: 'monospace',
lineHeight: 1.5,
fontSize: theme.fontSizes.smallBody,
},
}));
type StrategyIds = { strategyIds: string[] };
interface IDiffProps {
preData: StrategyIds;
@ -20,18 +6,12 @@ interface IDiffProps {
}
export const EnvironmentStrategyOrderDiff = ({ preData, data }: IDiffProps) => {
const useNewDiff = useUiFlag('improvedJsonDiff');
const Wrapper = useNewDiff ? Fragment : StyledCodeSection;
return (
<Wrapper>
<EventDiff
entry={{
preData: preData.strategyIds,
data: data.strategyIds,
}}
sort={(a, b) => a.index - b.index}
/>
</Wrapper>
<EventDiff
entry={{
preData: preData.strategyIds,
data: data.strategyIds,
}}
/>
);
};

View File

@ -10,7 +10,7 @@ import type {
import { useReleasePlanPreview } from 'hooks/useReleasePlanPreview';
import { useReleasePlans } from 'hooks/api/getters/useReleasePlans/useReleasePlans';
import { TooltipLink } from 'component/common/TooltipLink/TooltipLink';
import EventDiff from 'component/events/EventDiff/EventDiff';
import { EventDiff } from 'component/events/EventDiff/EventDiff';
import { ReleasePlan } from 'component/feature/FeatureView/FeatureOverview/ReleasePlan/ReleasePlan';
import { ReleasePlanMilestone } from 'component/feature/FeatureView/FeatureOverview/ReleasePlan/ReleasePlanMilestone/ReleasePlanMilestone';
import type { IReleasePlan } from 'interfaces/releasePlans';

View File

@ -27,12 +27,6 @@ const strategy = {
};
const setupApi = () => {
testServerRoute(server, '/api/admin/ui-config', {
flags: {
improvedJsonDiff: true,
},
});
testServerRoute(
server,
`/api/admin/projects/${projectId}/features/${feature}`,

View File

@ -1,5 +1,5 @@
import { styled } from '@mui/material';
import EventDiff from 'component/events/EventDiff/EventDiff';
import { EventDiff } from 'component/events/EventDiff/EventDiff';
import type { IFeatureVariant } from 'interfaces/featureToggle';
const StyledCodeSection = styled('div')(({ theme }) => ({
@ -31,7 +31,6 @@ export const VariantDiff = ({ preData, data }: IDiffProps) => (
preData: variantsArrayToObject(preData),
data: variantsArrayToObject(data),
}}
sort={(a, b) => a.index - b.index}
/>
</StyledCodeSection>
);

View File

@ -1,5 +1,5 @@
import { Typography, Button, useTheme, useMediaQuery } from '@mui/material';
import EventDiff from 'component/events/EventDiff/EventDiff';
import { EventDiff } from 'component/events/EventDiff/EventDiff';
import {
fadeInBottomEnter,
fadeInBottomStartWithoutFixed,

View File

@ -1,4 +1,4 @@
import EventDiff from 'component/events/EventDiff/EventDiff';
import { EventDiff } from 'component/events/EventDiff/EventDiff';
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
import { useLocationSettings } from 'hooks/useLocationSettings';
import { formatDateYMDHMS } from 'utils/formatDate';

View File

@ -1,23 +1,27 @@
import { render } from 'utils/testRenderer';
import { screen } from '@testing-library/react';
import EventDiff from './EventDiff.tsx';
import { EventDiff } from './EventDiff.tsx';
test('Show no changes', async () => {
render(<EventDiff entry={{ preData: [], data: [] }} />);
expect(screen.getByText('(no changes)')).toBeInTheDocument();
const { container } = render(
<EventDiff entry={{ preData: [{ a: 'b' }], data: [{ a: 'b' }] }} />,
);
const diff = container.querySelector('.diff');
expect(diff).toBeEmptyDOMElement();
});
test('Show new data added diff', async () => {
render(<EventDiff entry={{ preData: {}, data: { segments: [] } }} />);
expect(screen.getByText('+ segments: []')).toBeInTheDocument();
const element = await screen.findByText(/segments:.*/);
expect(element).toHaveClass('addition');
});
test('Show new data removed diff', async () => {
render(<EventDiff entry={{ preData: { segments: [] }, data: {} }} />);
expect(screen.getByText('- segments (deleted)')).toBeInTheDocument();
const element = await screen.findByText(/segments:.*/);
expect(element).toHaveClass('deletion');
});
test('Show new data changes diff', async () => {
@ -27,8 +31,10 @@ test('Show new data changes diff', async () => {
/>,
);
expect(screen.getByText('- segments: "a"')).toBeInTheDocument();
expect(screen.getByText('+ segments: "b"')).toBeInTheDocument();
const deleted = await screen.findByText(/segments: "a".*/);
expect(deleted).toHaveClass('deletion');
const added = await screen.findByText(/segments: "b".*/);
expect(added).toHaveClass('addition');
});
test('Show new data only', async () => {
@ -36,7 +42,8 @@ test('Show new data only', async () => {
<EventDiff entry={{ preData: undefined, data: { segments: [] } }} />,
);
expect(screen.getByText('{ "segments": [] }')).toBeInTheDocument();
const element = await screen.findByText(/segments:.*/);
expect(element).toHaveClass('addition');
});
test('Show old data only', async () => {
@ -44,5 +51,6 @@ test('Show old data only', async () => {
<EventDiff entry={{ preData: { segments: [] }, data: undefined }} />,
);
expect(screen.getByText('{ "segments": [] }')).toBeInTheDocument();
const element = await screen.findByText(/segments:.*/);
expect(element).toHaveClass('deletion');
});

View File

@ -1,28 +1,9 @@
import { diff } from 'deep-diff';
import { type JSX, type CSSProperties, useState, type FC, useId } from 'react';
import { useState, type FC, useId } from 'react';
import { JsonDiffComponent, type JsonValue } from 'json-diff-react';
import { Button, styled, useTheme } from '@mui/material';
import { useUiFlag } from 'hooks/useUiFlag';
const DIFF_PREFIXES: Record<string, string> = {
A: ' ',
E: ' ',
D: '-',
N: '+',
};
interface IEventDiffResult {
key: string;
value: JSX.Element;
index: number;
}
import { Button, styled } from '@mui/material';
interface IEventDiffProps {
entry: { data?: unknown; preData?: unknown };
/**
* @deprecated remove with flag improvedJsonDiff
*/
sort?: (a: IEventDiffResult, b: IEventDiffResult) => number;
excludeKeys?: string[];
}
@ -78,7 +59,7 @@ const ButtonIcon = styled('span')(({ theme }) => ({
marginInlineEnd: theme.spacing(0.5),
}));
export const NewEventDiff: FC<IEventDiffProps> = ({ entry, excludeKeys }) => {
export const EventDiff: FC<IEventDiffProps> = ({ entry, excludeKeys }) => {
const changeType = entry.preData && entry.data ? 'edit' : 'replacement';
const showExpandButton = changeType === 'edit';
const [full, setFull] = useState(false);
@ -112,115 +93,3 @@ export const NewEventDiff: FC<IEventDiffProps> = ({ entry, excludeKeys }) => {
</>
);
};
const OldEventDiff: FC<IEventDiffProps> = ({
entry,
sort = (a, b) => a.key.localeCompare(b.key),
}: IEventDiffProps) => {
const theme = useTheme();
const styles: Record<string, CSSProperties> = {
A: { color: theme.palette.eventLog.edited }, // array edited
E: { color: theme.palette.eventLog.edited }, // edited
D: { color: theme.palette.eventLog.diffSub }, // deleted
N: { color: theme.palette.eventLog.diffAdd }, // added
};
const diffs =
entry.data && entry.preData
? diff(entry.preData, entry.data)
: undefined;
const buildItemDiff = (diff: any, key: string) => {
let change: JSX.Element | undefined;
if (diff.lhs !== undefined) {
change = (
<div style={styles.D}>
- {key}: {JSON.stringify(diff.lhs)}
</div>
);
} else if (diff.rhs !== undefined) {
change = (
<div style={styles.N}>
+ {key}: {JSON.stringify(diff.rhs)}
</div>
);
}
return change;
};
const buildDiff = (diff: any, index: number): IEventDiffResult => {
let change: JSX.Element | undefined;
const key = diff.path?.join('.') ?? diff.index;
if (diff.item) {
change = buildItemDiff(diff.item, key);
} else if (diff.lhs !== undefined && diff.rhs !== undefined) {
change = (
<div>
<div style={styles.D}>
- {key}: {JSON.stringify(diff.lhs)}
</div>
<div style={styles.N}>
+ {key}: {JSON.stringify(diff.rhs)}
</div>
</div>
);
} else {
const changeValue = JSON.stringify(diff.rhs || diff.item);
change = (
<div style={styles[diff.kind]}>
{DIFF_PREFIXES[diff.kind]} {key}
{changeValue
? `: ${changeValue}`
: diff.kind === 'D'
? ' (deleted)'
: ''}
</div>
);
}
return {
key: key.toString(),
value: <div key={index}>{change}</div>,
index,
};
};
let changes: any[] = [];
if (diffs) {
changes = diffs
.map(buildDiff)
.sort(sort)
.map(({ value }) => value);
} else if (entry.data == null || entry.preData == null) {
// Just show the data if there is no diff yet.
const data = entry.data || entry.preData;
changes = [
<div key={0} style={entry.data ? styles.N : styles.D}>
{JSON.stringify(data, null, 2)}
</div>,
];
}
return (
<pre style={{ overflowX: 'auto', overflowY: 'hidden' }}>
<code>{changes.length === 0 ? '(no changes)' : changes}</code>
</pre>
);
};
export const EventDiff: FC<IEventDiffProps> = (props) => {
const useNewJsonDiff = useUiFlag('improvedJsonDiff');
if (useNewJsonDiff) {
return <NewEventDiff {...props} />;
}
return <OldEventDiff {...props} />;
};
/**
* @deprecated remove the default export with flag improvedJsonDiff. Switch imports in files that use this to the named import instead.
*/
export default EventDiff;

View File

@ -88,7 +88,6 @@ export type UiFlags = {
customMetrics?: boolean;
lifecycleMetrics?: boolean;
createFlagDialogCache?: boolean;
improvedJsonDiff?: boolean;
impactMetrics?: boolean;
crDiffView?: boolean;
changeRequestApproverEmails?: boolean;

View File

@ -0,0 +1 @@
{}

View File

@ -54,7 +54,7 @@ export class MetricsTranslator {
): Record<string, string | number> {
return {
...(sample.labels || {}),
origin: (sample.labels && sample.labels.origin) || 'sdk',
origin: sample.labels?.origin || 'sdk',
};
}

View File

@ -58,7 +58,6 @@ export type IFlagKey =
| 'customMetrics'
| 'impactMetrics'
| 'createFlagDialogCache'
| 'improvedJsonDiff'
| 'crDiffView'
| 'changeRequestApproverEmails'
| 'paygTrialEvents'
@ -275,10 +274,6 @@ const flags: IFlags = {
process.env.UNLEASH_EXPERIMENTAL_CHANGE_REQUEST_APPROVER_EMAILS,
false,
),
improvedJsonDiff: parseEnvVarBoolean(
process.env.UNLEASH_EXPERIMENTAL_IMPROVED_JSON_DIFF,
false,
),
crDiffView: parseEnvVarBoolean(
process.env.UNLEASH_EXPERIMENTAL_CR_DIFF_VIEW,
false,

View File

@ -54,7 +54,6 @@ process.nextTick(async () => {
reportUnknownFlags: true,
customMetrics: true,
lifecycleMetrics: true,
improvedJsonDiff: true,
impactMetrics: true,
crDiffView: true,
paygTrialEvents: true,