diff --git a/src/lib/features/feature-search/feature-search-store.ts b/src/lib/features/feature-search/feature-search-store.ts index 7bc944fe1577..76bfc84deb2b 100644 --- a/src/lib/features/feature-search/feature-search-store.ts +++ b/src/lib/features/feature-search/feature-search-store.ts @@ -604,11 +604,11 @@ const applyMultiQueryParams = ( ): void => { queryParams.forEach((param) => { const values = param.values.map((val) => - (Array.isArray(fields) ? val.split(':') : [val]).map((s) => - s.trim(), - ), + (Array.isArray(fields) + ? val.split(/:(.+)/).filter(Boolean) + : [val] + ).map((s) => s.trim()), ); - const baseSubQuery = createBaseQuery(values); switch (param.operator) { 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 86a8ee7d495a..34f116daef5c 100644 --- a/src/lib/features/feature-search/feature.search.e2e.test.ts +++ b/src/lib/features/feature-search/feature.search.e2e.test.ts @@ -359,6 +359,20 @@ test('should filter features by tag', async () => { await filterFeaturesByTag('EXCLUDE_ALL:simple,simple:jest', 400); }); +test('should filter features by tag that has colon inside', async () => { + await app.createFeature('my_feature_a'); + await app.addTag('my_feature_a', { + type: 'simple', + value: 'my_tag:colon', + }); + + const { body } = await filterFeaturesByTag('INCLUDE:simple:my_tag:colon'); + + expect(body).toMatchObject({ + features: [{ name: 'my_feature_a' }], + }); +}); + test('should filter features by environment status', async () => { await app.createFeature('my_feature_a'); await app.createFeature('my_feature_b'); diff --git a/src/lib/openapi/spec/feature-search-query-parameters.ts b/src/lib/openapi/spec/feature-search-query-parameters.ts index bed2b45b2d3c..0de66e97ec88 100644 --- a/src/lib/openapi/spec/feature-search-query-parameters.ts +++ b/src/lib/openapi/spec/feature-search-query-parameters.ts @@ -63,7 +63,7 @@ export const featureSearchQueryParameters = [ schema: { type: 'string', pattern: - '^(INCLUDE|DO_NOT_INCLUDE|INCLUDE_ALL_OF|INCLUDE_ANY_OF|EXCLUDE_IF_ANY_OF|EXCLUDE_ALL):(?:\\s*[^,:]+:[^,:]+\\s*)(?:,\\s*[^,:]+:[^,:]+\\s*)*$', + '^(INCLUDE|DO_NOT_INCLUDE|INCLUDE_ALL_OF|INCLUDE_ANY_OF|EXCLUDE_IF_ANY_OF|EXCLUDE_ALL):([^:,]+:.+?)(,\\s*[^:,]+:.+?)*$', example: 'INCLUDE:simple:my_tag', }, description: