1
0
mirror of https://github.com/Unleash/unleash.git synced 2025-07-21 13:47:39 +02:00

feat: now updating/editing strategy will store constraints in recents (#9861)

This commit is contained in:
Jaanus Sellin 2025-04-29 15:33:06 +03:00 committed by GitHub
parent 7356453c0c
commit cb987ac78b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 99 additions and 31 deletions

View File

@ -15,7 +15,7 @@ import { EditableConstraintsList } from 'component/common/NewConstraintAccordion
import { Limit } from 'component/common/Limit/Limit';
import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig';
import { useUiFlag } from 'hooks/useUiFlag';
import { RecentlyUsedConstraints } from '../RecentlyUsedConstraints';
import { RecentlyUsedConstraints } from '../RecentlyUsedConstraints/RecentlyUsedConstraints';
interface IConstraintAccordionListProps {
constraints: IConstraint[];

View File

@ -26,7 +26,6 @@ const StyledConstraintsContainer = styled('div')(({ theme }) => ({
export const RecentlyUsedConstraints = ({
temporary,
}: IRecentlyUsedConstraintsProps) => {
// Mock constraint for now
const mockConstraints: IConstraint[] = [
{
contextName: 'userId',

View File

@ -91,9 +91,7 @@ describe('useRecentlyUsedConstraints', () => {
});
it('should initialize with empty array when no items in localStorage', () => {
const { result } = renderHook(() =>
useRecentlyUsedConstraints('test-key'),
);
const { result } = renderHook(() => useRecentlyUsedConstraints());
expect(result.current.items).toEqual([]);
});
@ -101,16 +99,14 @@ describe('useRecentlyUsedConstraints', () => {
it('should initialize with initial items if provided', () => {
const initialItems = [createTestConstraint('userId')];
const { result } = renderHook(() =>
useRecentlyUsedConstraints('test-key', initialItems),
useRecentlyUsedConstraints(initialItems),
);
expect(result.current.items).toEqual(initialItems);
});
it('should add new items to the beginning of the list', () => {
const { result } = renderHook(() =>
useRecentlyUsedConstraints('test-key'),
);
const { result } = renderHook(() => useRecentlyUsedConstraints());
act(() => {
result.current.addItem(createTestConstraint('userId'));
@ -124,10 +120,27 @@ describe('useRecentlyUsedConstraints', () => {
expect(result.current.items[1].contextName).toBe('userId');
});
it('should handle array of constraints when adding items', () => {
const { result } = renderHook(() => useRecentlyUsedConstraints());
const constraints = [
createTestConstraint('userId'),
createTestConstraint('email'),
createTestConstraint('appName'),
];
act(() => {
result.current.addItem(constraints);
});
expect(result.current.items.length).toBe(3);
expect(result.current.items[0].contextName).toBe('appName');
expect(result.current.items[1].contextName).toBe('email');
expect(result.current.items[2].contextName).toBe('userId');
});
it('should limit stored items to maximum of 3', () => {
const { result } = renderHook(() =>
useRecentlyUsedConstraints('test-key'),
);
const { result } = renderHook(() => useRecentlyUsedConstraints());
act(() => {
result.current.addItem(createTestConstraint('userId'));
@ -142,10 +155,25 @@ describe('useRecentlyUsedConstraints', () => {
expect(result.current.items[2].contextName).toBe('email');
});
it('should also limit to max of 3 items when adding an array of constraints', () => {
const { result } = renderHook(() => useRecentlyUsedConstraints());
const constraints = [
createTestConstraint('userId'),
createTestConstraint('email'),
createTestConstraint('appName'),
createTestConstraint('countryId'),
];
act(() => {
result.current.addItem(constraints);
});
expect(result.current.items.length).toBe(3);
});
it('should not add duplicate constraints', () => {
const { result } = renderHook(() =>
useRecentlyUsedConstraints('test-key'),
);
const { result } = renderHook(() => useRecentlyUsedConstraints());
const constraint1 = createTestConstraint('userId', IN, [
'user1',
@ -173,9 +201,7 @@ describe('useRecentlyUsedConstraints', () => {
});
it('should not add duplicate constraints with values in different order', () => {
const { result } = renderHook(() =>
useRecentlyUsedConstraints('test-key'),
);
const { result } = renderHook(() => useRecentlyUsedConstraints());
const constraint1 = {
contextName: 'userId',
@ -210,17 +236,33 @@ describe('useRecentlyUsedConstraints', () => {
]);
});
it('should handle duplicates in an array of constraints', () => {
const { result } = renderHook(() => useRecentlyUsedConstraints());
const constraints = [
createTestConstraint('userId', IN, ['user1', 'user2']),
createTestConstraint('email'),
createTestConstraint('userId', IN, ['user1', 'user2']), // Duplicate
];
act(() => {
result.current.addItem(constraints);
});
expect(result.current.items.length).toBe(2);
expect(result.current.items[0].contextName).toBe('userId');
expect(result.current.items[1].contextName).toBe('email');
});
it('should persist items to localStorage', () => {
const { result } = renderHook(() =>
useRecentlyUsedConstraints('test-key'),
);
const { result } = renderHook(() => useRecentlyUsedConstraints());
act(() => {
result.current.addItem(createTestConstraint('userId'));
});
const { result: newResult } = renderHook(() =>
useRecentlyUsedConstraints('test-key'),
useRecentlyUsedConstraints(),
);
expect(newResult.current.items[0].contextName).toBe('userId');

View File

@ -5,7 +5,6 @@ export const areConstraintsEqual = (
a: IConstraint,
b: IConstraint,
): boolean => {
// Sort the values arrays if they exist
const sortedValues = (values?: string[]) =>
values ? [...values].sort() : undefined;
@ -31,21 +30,25 @@ export const areConstraintsEqual = (
};
export const useRecentlyUsedConstraints = (
key: string,
initialItems: IConstraint[] = [],
) => {
const [items, setItems] = useLocalStorageState<IConstraint[]>(
`recently-used-constraints-${key}`,
'recently-used-constraints',
initialItems,
);
const addItem = (newItem: IConstraint) => {
const addItem = (newItem: IConstraint | IConstraint[]) => {
setItems((prevItems) => {
const filteredItems = prevItems.filter(
(item) => !areConstraintsEqual(item, newItem),
);
const itemsToAdd = Array.isArray(newItem) ? newItem : [newItem];
const updatedItems = [newItem, ...filteredItems];
let updatedItems = [...prevItems];
itemsToAdd.forEach((item) => {
updatedItems = updatedItems.filter(
(existingItem) => !areConstraintsEqual(existingItem, item),
);
updatedItems = [item, ...updatedItems];
});
return updatedItems.slice(0, 3);
});
};

View File

@ -4,12 +4,18 @@ import type {
IFeatureStrategySortOrder,
} from 'interfaces/strategy';
import useAPI from '../useApi/useApi';
import { useRecentlyUsedConstraints } from 'component/feature/FeatureStrategy/FeatureStrategyConstraints/RecentlyUsedConstraints/useRecentlyUsedConstraints';
import { useUiFlag } from 'hooks/useUiFlag';
const useFeatureStrategyApi = () => {
const { makeRequest, createRequest, errors, loading } = useAPI({
propagateErrors: true,
});
const { addItem: addToRecentlyUsedConstraints } =
useRecentlyUsedConstraints();
const addEditStrategyEnabled = useUiFlag('addEditStrategy');
const addStrategyToFeature = async (
projectId: string,
featureId: string,
@ -22,7 +28,17 @@ const useFeatureStrategyApi = () => {
{ method: 'POST', body: JSON.stringify(payload) },
'addStrategyToFeature',
);
return (await makeRequest(req.caller, req.id)).json();
const result = await makeRequest(req.caller, req.id);
if (
addEditStrategyEnabled &&
payload.constraints &&
payload.constraints.length > 0
) {
addToRecentlyUsedConstraints(payload.constraints);
}
return result.json();
};
const deleteStrategyFromFeature = async (
@ -54,6 +70,14 @@ const useFeatureStrategyApi = () => {
'updateStrategyOnFeature',
);
await makeRequest(req.caller, req.id);
if (
addEditStrategyEnabled &&
payload.constraints &&
payload.constraints.length > 0
) {
addToRecentlyUsedConstraints(payload.constraints);
}
};
const setStrategiesSortOrder = async (