diff --git a/src/lib/features/feature-search/feature-search-service.ts b/src/lib/features/feature-search/feature-search-service.ts index f4fc5de85c..2d9ed8a827 100644 --- a/src/lib/features/feature-search/feature-search-service.ts +++ b/src/lib/features/feature-search/feature-search-service.ts @@ -75,6 +75,14 @@ export class FeatureSearchService { if (parsed) queryParams.push(parsed); } + if (params.type) { + const parsed = this.parseOperatorValue( + 'features.type', + params.type, + ); + if (parsed) queryParams.push(parsed); + } + ['tag', 'segment', 'project'].forEach((field) => { if (params[field]) { const parsed = this.parseOperatorValue(field, params[field]); diff --git a/src/lib/features/feature-search/feature-search-store.ts b/src/lib/features/feature-search/feature-search-store.ts index e58991fa37..60fa1a111b 100644 --- a/src/lib/features/feature-search/feature-search-store.ts +++ b/src/lib/features/feature-search/feature-search-store.ts @@ -93,7 +93,6 @@ class FeatureSearchStore implements IFeatureSearchStore { { userId, searchParams, - type, status, offset, limit, @@ -175,10 +174,6 @@ class FeatureSearchStore implements IFeatureSearchStore { 'features.description', ]); - if (type) { - query.whereIn('features.type', type); - } - if (status && status.length > 0) { query.where((builder) => { for (const [envName, envStatus] of status) { diff --git a/src/lib/features/feature-search/feature.search.e2e.test.ts b/src/lib/features/feature-search/feature.search.e2e.test.ts index 33d78ba3fc..6d5c0af4cf 100644 --- a/src/lib/features/feature-search/feature.search.e2e.test.ts +++ b/src/lib/features/feature-search/feature.search.e2e.test.ts @@ -102,10 +102,9 @@ const searchFeaturesWithOffset = async ( .expect(expectedCode); }; -const filterFeaturesByType = async (types: string[], expectedCode = 200) => { - const typeParams = types.map((type) => `type[]=${type}`).join('&'); +const filterFeaturesByType = async (typeParams: string, expectedCode = 200) => { return app.request - .get(`/api/admin/search/features?${typeParams}`) + .get(`/api/admin/search/features?type=${typeParams}`) .expect(expectedCode); }; @@ -219,10 +218,9 @@ test('should filter features by type', async () => { type: 'experimental', }); - const { body } = await filterFeaturesByType([ - 'experimental', - 'kill-switch', - ]); + const { body } = await filterFeaturesByType( + 'IS_ANY_OF:experimental,kill-switch', + ); expect(body).toMatchObject({ features: [{ name: 'my_feature_b' }], diff --git a/src/lib/features/feature-toggle/types/feature-toggle-strategies-store-type.ts b/src/lib/features/feature-toggle/types/feature-toggle-strategies-store-type.ts index 71ec9f9323..dd3bc8ccb9 100644 --- a/src/lib/features/feature-toggle/types/feature-toggle-strategies-store-type.ts +++ b/src/lib/features/feature-toggle/types/feature-toggle-strategies-store-type.ts @@ -27,7 +27,7 @@ export interface IFeatureSearchParams { segment?: string; createdAt?: string; state?: string; - type?: string[]; + type?: string; tag?: string; status?: string[][]; offset: number; diff --git a/src/lib/openapi/spec/feature-search-query-parameters.ts b/src/lib/openapi/spec/feature-search-query-parameters.ts index 472b79673e..91f450c03e 100644 --- a/src/lib/openapi/spec/feature-search-query-parameters.ts +++ b/src/lib/openapi/spec/feature-search-query-parameters.ts @@ -37,13 +37,13 @@ export const featureSearchQueryParameters = [ { name: 'type', schema: { - type: 'array', - items: { - type: 'string', - example: 'release', - }, + type: 'string', + example: 'IS:release', + pattern: + '^(IS|IS_NOT|IS_ANY_OF|IS_NONE_OF):(.*?)(,([a-zA-Z0-9_]+))*$', }, - description: 'The list of feature types to filter by', + description: + 'The feature flag type to filter by. The type can be specified with an operator. The supported operators are IS, IS_NOT, IS_ANY_OF, IS_NONE_OF.', in: 'query', }, {