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:
parent
7356453c0c
commit
cb987ac78b
@ -15,7 +15,7 @@ import { EditableConstraintsList } from 'component/common/NewConstraintAccordion
|
|||||||
import { Limit } from 'component/common/Limit/Limit';
|
import { Limit } from 'component/common/Limit/Limit';
|
||||||
import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig';
|
import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig';
|
||||||
import { useUiFlag } from 'hooks/useUiFlag';
|
import { useUiFlag } from 'hooks/useUiFlag';
|
||||||
import { RecentlyUsedConstraints } from '../RecentlyUsedConstraints';
|
import { RecentlyUsedConstraints } from '../RecentlyUsedConstraints/RecentlyUsedConstraints';
|
||||||
|
|
||||||
interface IConstraintAccordionListProps {
|
interface IConstraintAccordionListProps {
|
||||||
constraints: IConstraint[];
|
constraints: IConstraint[];
|
||||||
|
@ -26,7 +26,6 @@ const StyledConstraintsContainer = styled('div')(({ theme }) => ({
|
|||||||
export const RecentlyUsedConstraints = ({
|
export const RecentlyUsedConstraints = ({
|
||||||
temporary,
|
temporary,
|
||||||
}: IRecentlyUsedConstraintsProps) => {
|
}: IRecentlyUsedConstraintsProps) => {
|
||||||
// Mock constraint for now
|
|
||||||
const mockConstraints: IConstraint[] = [
|
const mockConstraints: IConstraint[] = [
|
||||||
{
|
{
|
||||||
contextName: 'userId',
|
contextName: 'userId',
|
@ -91,9 +91,7 @@ describe('useRecentlyUsedConstraints', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should initialize with empty array when no items in localStorage', () => {
|
it('should initialize with empty array when no items in localStorage', () => {
|
||||||
const { result } = renderHook(() =>
|
const { result } = renderHook(() => useRecentlyUsedConstraints());
|
||||||
useRecentlyUsedConstraints('test-key'),
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(result.current.items).toEqual([]);
|
expect(result.current.items).toEqual([]);
|
||||||
});
|
});
|
||||||
@ -101,16 +99,14 @@ describe('useRecentlyUsedConstraints', () => {
|
|||||||
it('should initialize with initial items if provided', () => {
|
it('should initialize with initial items if provided', () => {
|
||||||
const initialItems = [createTestConstraint('userId')];
|
const initialItems = [createTestConstraint('userId')];
|
||||||
const { result } = renderHook(() =>
|
const { result } = renderHook(() =>
|
||||||
useRecentlyUsedConstraints('test-key', initialItems),
|
useRecentlyUsedConstraints(initialItems),
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(result.current.items).toEqual(initialItems);
|
expect(result.current.items).toEqual(initialItems);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should add new items to the beginning of the list', () => {
|
it('should add new items to the beginning of the list', () => {
|
||||||
const { result } = renderHook(() =>
|
const { result } = renderHook(() => useRecentlyUsedConstraints());
|
||||||
useRecentlyUsedConstraints('test-key'),
|
|
||||||
);
|
|
||||||
|
|
||||||
act(() => {
|
act(() => {
|
||||||
result.current.addItem(createTestConstraint('userId'));
|
result.current.addItem(createTestConstraint('userId'));
|
||||||
@ -124,10 +120,27 @@ describe('useRecentlyUsedConstraints', () => {
|
|||||||
expect(result.current.items[1].contextName).toBe('userId');
|
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', () => {
|
it('should limit stored items to maximum of 3', () => {
|
||||||
const { result } = renderHook(() =>
|
const { result } = renderHook(() => useRecentlyUsedConstraints());
|
||||||
useRecentlyUsedConstraints('test-key'),
|
|
||||||
);
|
|
||||||
|
|
||||||
act(() => {
|
act(() => {
|
||||||
result.current.addItem(createTestConstraint('userId'));
|
result.current.addItem(createTestConstraint('userId'));
|
||||||
@ -142,10 +155,25 @@ describe('useRecentlyUsedConstraints', () => {
|
|||||||
expect(result.current.items[2].contextName).toBe('email');
|
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', () => {
|
it('should not add duplicate constraints', () => {
|
||||||
const { result } = renderHook(() =>
|
const { result } = renderHook(() => useRecentlyUsedConstraints());
|
||||||
useRecentlyUsedConstraints('test-key'),
|
|
||||||
);
|
|
||||||
|
|
||||||
const constraint1 = createTestConstraint('userId', IN, [
|
const constraint1 = createTestConstraint('userId', IN, [
|
||||||
'user1',
|
'user1',
|
||||||
@ -173,9 +201,7 @@ describe('useRecentlyUsedConstraints', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should not add duplicate constraints with values in different order', () => {
|
it('should not add duplicate constraints with values in different order', () => {
|
||||||
const { result } = renderHook(() =>
|
const { result } = renderHook(() => useRecentlyUsedConstraints());
|
||||||
useRecentlyUsedConstraints('test-key'),
|
|
||||||
);
|
|
||||||
|
|
||||||
const constraint1 = {
|
const constraint1 = {
|
||||||
contextName: 'userId',
|
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', () => {
|
it('should persist items to localStorage', () => {
|
||||||
const { result } = renderHook(() =>
|
const { result } = renderHook(() => useRecentlyUsedConstraints());
|
||||||
useRecentlyUsedConstraints('test-key'),
|
|
||||||
);
|
|
||||||
|
|
||||||
act(() => {
|
act(() => {
|
||||||
result.current.addItem(createTestConstraint('userId'));
|
result.current.addItem(createTestConstraint('userId'));
|
||||||
});
|
});
|
||||||
|
|
||||||
const { result: newResult } = renderHook(() =>
|
const { result: newResult } = renderHook(() =>
|
||||||
useRecentlyUsedConstraints('test-key'),
|
useRecentlyUsedConstraints(),
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(newResult.current.items[0].contextName).toBe('userId');
|
expect(newResult.current.items[0].contextName).toBe('userId');
|
@ -5,7 +5,6 @@ export const areConstraintsEqual = (
|
|||||||
a: IConstraint,
|
a: IConstraint,
|
||||||
b: IConstraint,
|
b: IConstraint,
|
||||||
): boolean => {
|
): boolean => {
|
||||||
// Sort the values arrays if they exist
|
|
||||||
const sortedValues = (values?: string[]) =>
|
const sortedValues = (values?: string[]) =>
|
||||||
values ? [...values].sort() : undefined;
|
values ? [...values].sort() : undefined;
|
||||||
|
|
||||||
@ -31,21 +30,25 @@ export const areConstraintsEqual = (
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const useRecentlyUsedConstraints = (
|
export const useRecentlyUsedConstraints = (
|
||||||
key: string,
|
|
||||||
initialItems: IConstraint[] = [],
|
initialItems: IConstraint[] = [],
|
||||||
) => {
|
) => {
|
||||||
const [items, setItems] = useLocalStorageState<IConstraint[]>(
|
const [items, setItems] = useLocalStorageState<IConstraint[]>(
|
||||||
`recently-used-constraints-${key}`,
|
'recently-used-constraints',
|
||||||
initialItems,
|
initialItems,
|
||||||
);
|
);
|
||||||
|
|
||||||
const addItem = (newItem: IConstraint) => {
|
const addItem = (newItem: IConstraint | IConstraint[]) => {
|
||||||
setItems((prevItems) => {
|
setItems((prevItems) => {
|
||||||
const filteredItems = prevItems.filter(
|
const itemsToAdd = Array.isArray(newItem) ? newItem : [newItem];
|
||||||
(item) => !areConstraintsEqual(item, 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);
|
return updatedItems.slice(0, 3);
|
||||||
});
|
});
|
||||||
};
|
};
|
@ -4,12 +4,18 @@ import type {
|
|||||||
IFeatureStrategySortOrder,
|
IFeatureStrategySortOrder,
|
||||||
} from 'interfaces/strategy';
|
} from 'interfaces/strategy';
|
||||||
import useAPI from '../useApi/useApi';
|
import useAPI from '../useApi/useApi';
|
||||||
|
import { useRecentlyUsedConstraints } from 'component/feature/FeatureStrategy/FeatureStrategyConstraints/RecentlyUsedConstraints/useRecentlyUsedConstraints';
|
||||||
|
import { useUiFlag } from 'hooks/useUiFlag';
|
||||||
|
|
||||||
const useFeatureStrategyApi = () => {
|
const useFeatureStrategyApi = () => {
|
||||||
const { makeRequest, createRequest, errors, loading } = useAPI({
|
const { makeRequest, createRequest, errors, loading } = useAPI({
|
||||||
propagateErrors: true,
|
propagateErrors: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const { addItem: addToRecentlyUsedConstraints } =
|
||||||
|
useRecentlyUsedConstraints();
|
||||||
|
const addEditStrategyEnabled = useUiFlag('addEditStrategy');
|
||||||
|
|
||||||
const addStrategyToFeature = async (
|
const addStrategyToFeature = async (
|
||||||
projectId: string,
|
projectId: string,
|
||||||
featureId: string,
|
featureId: string,
|
||||||
@ -22,7 +28,17 @@ const useFeatureStrategyApi = () => {
|
|||||||
{ method: 'POST', body: JSON.stringify(payload) },
|
{ method: 'POST', body: JSON.stringify(payload) },
|
||||||
'addStrategyToFeature',
|
'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 (
|
const deleteStrategyFromFeature = async (
|
||||||
@ -54,6 +70,14 @@ const useFeatureStrategyApi = () => {
|
|||||||
'updateStrategyOnFeature',
|
'updateStrategyOnFeature',
|
||||||
);
|
);
|
||||||
await makeRequest(req.caller, req.id);
|
await makeRequest(req.caller, req.id);
|
||||||
|
|
||||||
|
if (
|
||||||
|
addEditStrategyEnabled &&
|
||||||
|
payload.constraints &&
|
||||||
|
payload.constraints.length > 0
|
||||||
|
) {
|
||||||
|
addToRecentlyUsedConstraints(payload.constraints);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const setStrategiesSortOrder = async (
|
const setStrategiesSortOrder = async (
|
||||||
|
Loading…
Reference in New Issue
Block a user