mirror of
https://github.com/Unleash/unleash.git
synced 2024-12-22 19:07:54 +01:00
feat: add operators for state filtering (#5497)
No changes in store needed, already utilizing reusable logic.
This commit is contained in:
parent
1aad9819cc
commit
a743ca0df6
@ -77,6 +77,7 @@ export default class FeatureSearchController extends Controller {
|
||||
type,
|
||||
tag,
|
||||
segment,
|
||||
state,
|
||||
status,
|
||||
offset,
|
||||
limit = '50',
|
||||
@ -110,6 +111,7 @@ export default class FeatureSearchController extends Controller {
|
||||
userId,
|
||||
tag,
|
||||
segment,
|
||||
state,
|
||||
status: normalizedStatus,
|
||||
offset: normalizedOffset,
|
||||
limit: normalizedLimit,
|
||||
|
@ -60,6 +60,16 @@ export class FeatureSearchService {
|
||||
convertToQueryParams = (params: IFeatureSearchParams): IQueryParam[] => {
|
||||
const queryParams: IQueryParam[] = [];
|
||||
|
||||
if (params.state) {
|
||||
const parsedState = this.parseOperatorValue('stale', params.state);
|
||||
if (parsedState) {
|
||||
parsedState.values = parsedState.values.map((value) =>
|
||||
value === 'active' ? 'false' : 'true',
|
||||
);
|
||||
queryParams.push(parsedState);
|
||||
}
|
||||
}
|
||||
|
||||
['tag', 'segment', 'project'].forEach((field) => {
|
||||
if (params[field]) {
|
||||
const parsed = this.parseOperatorValue(field, params[field]);
|
||||
|
@ -120,6 +120,12 @@ const filterFeaturesBySegment = async (segment: string, expectedCode = 200) => {
|
||||
.expect(expectedCode);
|
||||
};
|
||||
|
||||
const filterFeaturesByState = async (state: string, expectedCode = 200) => {
|
||||
return app.request
|
||||
.get(`/api/admin/search/features?state=${state}`)
|
||||
.expect(expectedCode);
|
||||
};
|
||||
|
||||
const filterFeaturesByEnvironmentStatus = async (
|
||||
environmentStatuses: string[],
|
||||
expectedCode = 200,
|
||||
@ -756,3 +762,37 @@ test('should filter features by segment', async () => {
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
test('should search features by state with operators', async () => {
|
||||
await app.createFeature({ name: 'my_feature_a', stale: false });
|
||||
await app.createFeature({ name: 'my_feature_b', stale: true });
|
||||
await app.createFeature({ name: 'my_feature_c', stale: true });
|
||||
|
||||
const { body } = await filterFeaturesByState('IS:active');
|
||||
expect(body).toMatchObject({
|
||||
features: [{ name: 'my_feature_a' }],
|
||||
});
|
||||
|
||||
const { body: isNotBody } = await filterFeaturesByState('IS_NOT:active');
|
||||
expect(isNotBody).toMatchObject({
|
||||
features: [{ name: 'my_feature_b' }, { name: 'my_feature_c' }],
|
||||
});
|
||||
|
||||
const { body: isAnyOfBody } = await filterFeaturesByState(
|
||||
'IS_ANY_OF:active, stale',
|
||||
);
|
||||
expect(isAnyOfBody).toMatchObject({
|
||||
features: [
|
||||
{ name: 'my_feature_a' },
|
||||
{ name: 'my_feature_b' },
|
||||
{ name: 'my_feature_c' },
|
||||
],
|
||||
});
|
||||
|
||||
const { body: isNotAnyBody } = await filterFeaturesByState(
|
||||
'IS_NOT_ANY_OF:active, stale',
|
||||
);
|
||||
expect(isNotAnyBody).toMatchObject({
|
||||
features: [],
|
||||
});
|
||||
});
|
||||
|
@ -748,7 +748,7 @@ class FeatureStrategiesStore implements IFeatureStrategiesStore {
|
||||
)
|
||||
.joinRaw('CROSS JOIN total_features')
|
||||
.whereBetween('final_rank', [offset + 1, offset + limit]);
|
||||
console.log(finalQuery.toQuery());
|
||||
|
||||
const rows = await finalQuery;
|
||||
|
||||
if (rows.length > 0) {
|
||||
|
@ -26,6 +26,7 @@ export interface IFeatureSearchParams {
|
||||
searchParams?: string[];
|
||||
project?: string;
|
||||
segment?: string;
|
||||
state?: string;
|
||||
type?: string[];
|
||||
tag?: string;
|
||||
status?: string[][];
|
||||
|
@ -21,6 +21,17 @@ export const featureSearchQueryParameters = [
|
||||
description: 'Id of the project where search and filter is performed',
|
||||
in: 'query',
|
||||
},
|
||||
{
|
||||
name: 'state',
|
||||
schema: {
|
||||
type: 'string',
|
||||
example: 'IS:active',
|
||||
pattern:
|
||||
'^(IS|IS_NOT|IS_ANY_OF|IS_NOT_ANY_OF):(.*?)(,([a-zA-Z0-9_]+))*$',
|
||||
},
|
||||
description: 'The state of the feature active/stale',
|
||||
in: 'query',
|
||||
},
|
||||
{
|
||||
name: 'type',
|
||||
schema: {
|
||||
|
@ -6,7 +6,11 @@ import { createTestConfig } from '../../config/test-config';
|
||||
import { IAuthType, IUnleashConfig } from '../../../lib/types/option';
|
||||
import { createServices } from '../../../lib/services';
|
||||
import sessionDb from '../../../lib/middleware/session-db';
|
||||
import { DEFAULT_PROJECT, IUnleashStores } from '../../../lib/types';
|
||||
import {
|
||||
DEFAULT_PROJECT,
|
||||
FeatureToggleDTO,
|
||||
IUnleashStores,
|
||||
} from '../../../lib/types';
|
||||
import { IUnleashServices } from '../../../lib/types/services';
|
||||
import { Db } from '../../../lib/db/db';
|
||||
import { IContextFieldDto } from 'lib/types/stores/context-field-store';
|
||||
@ -121,7 +125,7 @@ function httpApis(
|
||||
return request.post(url).send(postData).expect(expectStatusCode);
|
||||
},
|
||||
createFeature: (
|
||||
feature: string | CreateFeatureSchema,
|
||||
feature: string | FeatureToggleDTO,
|
||||
project: string = DEFAULT_PROJECT,
|
||||
expectedResponseCode: number = 201,
|
||||
) => {
|
||||
|
Loading…
Reference in New Issue
Block a user