Skip to content

Commit 0cbbd7d

Browse files
authored
Merge pull request #2716 from CarnegieLearningWeb/feature/2655-add-ids-to-search
Add ids to UI and search for segments, flags, and experiments
2 parents d114b94 + 4923d16 commit 0cbbd7d

File tree

15 files changed

+88
-42
lines changed

15 files changed

+88
-42
lines changed

backend/packages/Upgrade/src/api/controllers/validators/FeatureFlagsPaginatedParamsValidator.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ export enum FLAG_SEARCH_KEY {
2626
STATUS = 'status',
2727
TAG = 'tag',
2828
CONTEXT = 'context',
29+
ID = 'id',
2930
}
3031

3132
class IFeatureFlagSortParamsValidator {

backend/packages/Upgrade/src/api/controllers/validators/SegmentPaginatedParamsValidator.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ export enum SEGMENT_SEARCH_KEY {
2222
NAME = 'name',
2323
TAG = 'tag',
2424
CONTEXT = 'context',
25+
ID = 'id',
2526
}
2627

2728
class ISegmentSortParamsValidator {

backend/packages/Upgrade/src/api/services/ExperimentService.ts

Lines changed: 25 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ import { CacheService } from './CacheService';
8282
import { QueryService } from './QueryService';
8383
import { ArchivedStats } from '../models/ArchivedStats';
8484
import { ArchivedStatsRepository } from '../repositories/ArchivedStatsRepository';
85-
import { validate } from 'class-validator';
85+
import { isUUID, validate } from 'class-validator';
8686
import { plainToClass } from 'class-transformer';
8787
import { StratificationFactorRepository } from '../repositories/StratificationFactorRepository';
8888
import { ExperimentDetailsForCSVData } from '../repositories/AnalyticsRepository';
@@ -1797,33 +1797,43 @@ export class ExperimentService {
17971797
private paginatedSearchString(params: IExperimentSearchParams): string {
17981798
const type = params.key;
17991799
// escape % and ' characters
1800-
const serachString = params.string.replace(/%/g, '\\$&').replace(/'/g, "''");
1801-
const likeString = `ILIKE '%${serachString}%'`;
1802-
const searchString: string[] = [];
1800+
const searchString = params.string.replace(/%/g, '\\$&').replace(/'/g, "''");
1801+
if (type === EXPERIMENT_SEARCH_KEY.ID && !isUUID(searchString)) {
1802+
return '';
1803+
}
1804+
1805+
const likeString = `ILIKE '%${searchString}%'`;
1806+
const searchArray: string[] = [];
18031807
switch (type) {
18041808
case EXPERIMENT_SEARCH_KEY.NAME:
1805-
searchString.push(`${type} ${likeString}`);
1809+
searchArray.push(`${type} ${likeString}`);
18061810
break;
18071811
case EXPERIMENT_SEARCH_KEY.STATUS:
1808-
searchString.push(`state::TEXT ${likeString}`);
1812+
searchArray.push(`state::TEXT ${likeString}`);
18091813
break;
18101814
case EXPERIMENT_SEARCH_KEY.CONTEXT:
1811-
searchString.push(`ARRAY_TO_STRING(${type}, ',') ${likeString}`);
1815+
searchArray.push(`ARRAY_TO_STRING(${type}, ',') ${likeString}`);
18121816
break;
18131817
case EXPERIMENT_SEARCH_KEY.TAG:
1814-
searchString.push(`ARRAY_TO_STRING(tags, ',') ${likeString}`);
1818+
searchArray.push(`ARRAY_TO_STRING(tags, ',') ${likeString}`);
1819+
break;
1820+
case EXPERIMENT_SEARCH_KEY.ID:
1821+
searchArray.push(`experiment.id = '${searchString}'`);
18151822
break;
18161823
default:
1817-
searchString.push(`name ${likeString}`);
1818-
searchString.push(`state::TEXT ${likeString}`);
1819-
searchString.push(`ARRAY_TO_STRING(context, ',') ${likeString}`);
1820-
searchString.push(`ARRAY_TO_STRING(tags, ',') ${likeString}`);
1821-
searchString.push(`partitions.site ${likeString}`);
1822-
searchString.push(`partitions.target ${likeString}`);
1824+
searchArray.push(`name ${likeString}`);
1825+
searchArray.push(`state::TEXT ${likeString}`);
1826+
searchArray.push(`ARRAY_TO_STRING(context, ',') ${likeString}`);
1827+
searchArray.push(`ARRAY_TO_STRING(tags, ',') ${likeString}`);
1828+
searchArray.push(`partitions.site ${likeString}`);
1829+
searchArray.push(`partitions.target ${likeString}`);
1830+
if (isUUID(searchString)) {
1831+
searchArray.push(`experiment.id = '${searchString}'`);
1832+
}
18231833
break;
18241834
}
18251835

1826-
const searchStringConcatenated = `(${searchString.join(' OR ')})`;
1836+
const searchStringConcatenated = `(${searchArray.join(' OR ')})`;
18271837
return searchStringConcatenated;
18281838
}
18291839

backend/packages/Upgrade/src/api/services/FeatureFlagService.ts

Lines changed: 22 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ import { ExperimentAssignmentService } from './ExperimentAssignmentService';
4343
import { SegmentService } from './SegmentService';
4444
import { ErrorWithType } from '../errors/ErrorWithType';
4545
import { RequestedExperimentUser } from '../controllers/validators/ExperimentUserValidator';
46-
import { validate } from 'class-validator';
46+
import { isUUID, validate } from 'class-validator';
4747
import { plainToClass } from 'class-transformer';
4848
import {
4949
FeatureFlagImportDataValidation,
@@ -804,31 +804,40 @@ export class FeatureFlagService {
804804
private paginatedSearchString(params: IFeatureFlagSearchParams): string {
805805
const type = params.key;
806806
// escape % and ' characters
807-
const serachString = params.string.replace(/%/g, '\\$&').replace(/'/g, "''");
808-
const likeString = `ILIKE '%${serachString}%'`;
809-
const searchString: string[] = [];
807+
const searchString = params.string.replace(/%/g, '\\$&').replace(/'/g, "''");
808+
if (type === FLAG_SEARCH_KEY.ID && !isUUID(searchString)) {
809+
return '';
810+
}
811+
const likeString = `ILIKE '%${searchString}%'`;
812+
const searchArray: string[] = [];
810813
switch (type) {
811814
case FLAG_SEARCH_KEY.NAME:
812-
searchString.push(`${type} ${likeString}`);
815+
searchArray.push(`${type} ${likeString}`);
813816
break;
814817
case FLAG_SEARCH_KEY.STATUS:
815-
searchString.push(`status::TEXT ${likeString}`);
818+
searchArray.push(`status::TEXT ${likeString}`);
816819
break;
817820
case FLAG_SEARCH_KEY.CONTEXT:
818-
searchString.push(`ARRAY_TO_STRING(${type}, ',') ${likeString}`);
821+
searchArray.push(`ARRAY_TO_STRING(${type}, ',') ${likeString}`);
819822
break;
820823
case FLAG_SEARCH_KEY.TAG:
821-
searchString.push(`ARRAY_TO_STRING(tags, ',') ${likeString}`);
824+
searchArray.push(`ARRAY_TO_STRING(tags, ',') ${likeString}`);
825+
break;
826+
case FLAG_SEARCH_KEY.ID:
827+
searchArray.push(`feature_flag.id = '${searchString}'`);
822828
break;
823829
default:
824-
searchString.push(`name ${likeString}`);
825-
searchString.push(`status::TEXT ${likeString}`);
826-
searchString.push(`ARRAY_TO_STRING(context, ',') ${likeString}`);
827-
searchString.push(`ARRAY_TO_STRING(tags, ',') ${likeString}`);
830+
searchArray.push(`name ${likeString}`);
831+
searchArray.push(`status::TEXT ${likeString}`);
832+
searchArray.push(`ARRAY_TO_STRING(context, ',') ${likeString}`);
833+
searchArray.push(`ARRAY_TO_STRING(tags, ',') ${likeString}`);
834+
if (isUUID(searchString)) {
835+
searchArray.push(`feature_flag.id = '${searchString}'`);
836+
}
828837
break;
829838
}
830839

831-
const searchStringConcatenated = `(${searchString.join(' OR ')})`;
840+
const searchStringConcatenated = `(${searchArray.join(' OR ')})`;
832841
return searchStringConcatenated;
833842
}
834843

backend/packages/Upgrade/src/api/services/SegmentService.ts

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ import { FeatureFlagSegmentExclusionRepository } from '../repositories/FeatureFl
3838
import { FeatureFlagSegmentInclusionRepository } from '../repositories/FeatureFlagSegmentInclusionRepository';
3939
import { getSegmentData, getSegmentsData } from '../controllers/SegmentController';
4040
import { CacheService } from './CacheService';
41-
import { validate } from 'class-validator';
41+
import { isUUID, validate } from 'class-validator';
4242
import { plainToClass } from 'class-transformer';
4343
import path from 'path';
4444
import { GroupEnrollmentRepository } from '../repositories/GroupEnrollmentRepository';
@@ -222,7 +222,7 @@ export class SegmentService {
222222

223223
if (searchParams) {
224224
const whereClause = this.paginatedSearchString(searchParams);
225-
paginatedParentSubQuery = paginatedParentSubQuery.andWhere(whereClause);
225+
paginatedParentSubQuery = paginatedParentSubQuery.where(whereClause);
226226
}
227227
const countQuery = paginatedParentSubQuery.clone().andWhere('segment.type=:type', { type: SEGMENT_TYPE.PUBLIC });
228228
paginatedParentSubQuery = paginatedParentSubQuery.andWhere('segment.type = :type').offset(skip).limit(take);
@@ -245,24 +245,33 @@ export class SegmentService {
245245
private paginatedSearchString(params: ISegmentSearchParams): string {
246246
const type = params.key;
247247
// escape % and ' characters
248-
const serachString = params.string.replace(/%/g, '\\$&').replace(/'/g, "''");
249-
const likeString = `ILIKE '%${serachString}%'`;
250-
const searchString: string[] = [];
248+
const searchString = params.string.replace(/%/g, '\\$&').replace(/'/g, "''");
249+
if (type === SEGMENT_SEARCH_KEY.ID && !isUUID(searchString)) {
250+
return '';
251+
}
252+
const likeString = `ILIKE '%${searchString}%'`;
253+
const searchArray: string[] = [];
251254
switch (type) {
252255
case SEGMENT_SEARCH_KEY.NAME || SEGMENT_SEARCH_KEY.CONTEXT:
253-
searchString.push(`${type} ${likeString}`);
256+
searchArray.push(`${type} ${likeString}`);
254257
break;
255258
case SEGMENT_SEARCH_KEY.TAG:
256-
searchString.push(`ARRAY_TO_STRING(tags, ',') ${likeString}`);
259+
searchArray.push(`ARRAY_TO_STRING(tags, ',') ${likeString}`);
260+
break;
261+
case SEGMENT_SEARCH_KEY.ID:
262+
searchArray.push(`segment.id = '${searchString}'`);
257263
break;
258264
default:
259-
searchString.push(`${SEGMENT_SEARCH_KEY.NAME} ${likeString}`);
260-
searchString.push(`${SEGMENT_SEARCH_KEY.CONTEXT} ${likeString}`);
261-
searchString.push(`ARRAY_TO_STRING(tags, ',') ${likeString}`);
265+
searchArray.push(`${SEGMENT_SEARCH_KEY.NAME} ${likeString}`);
266+
searchArray.push(`${SEGMENT_SEARCH_KEY.CONTEXT} ${likeString}`);
267+
searchArray.push(`ARRAY_TO_STRING(tags, ',') ${likeString}`);
268+
if (isUUID(searchString)) {
269+
searchArray.push(`segment.id = '${searchString}'`);
270+
}
262271
break;
263272
}
264273

265-
const searchStringConcatenated = `(${searchString.join(' OR ')})`;
274+
const searchStringConcatenated = `(${searchArray.join(' OR ')})`;
266275
return searchStringConcatenated;
267276
}
268277

backend/packages/Upgrade/src/api/services/UserService.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -120,8 +120,8 @@ export class UserService {
120120
private paginatedSearchString(params: UserSearchParamsValidator): string {
121121
const type = params.key;
122122
// escape % and ' characters
123-
const serachString = params.string.replace(/%/g, '\\$&').replace(/'/g, "''");
124-
const likeString = `ILIKE '%${serachString}%'`;
123+
const searchString = params.string.replace(/%/g, '\\$&').replace(/'/g, "''");
124+
const likeString = `ILIKE '%${searchString}%'`;
125125
const likes: string[] = [];
126126
if (type === USER_SEARCH_SORT_KEY.ALL) {
127127
likes.push(`users.email::TEXT ${likeString}`);

frontend/projects/upgrade/src/app/features/dashboard/feature-flags/pages/feature-flag-details-page/feature-flag-details-page-content/feature-flag-overview-details-section-card/feature-flag-overview-details-section-card.component.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
[versionNumber]="flag.versionNumber"
99
[chipClass]="flag.status"
1010
[showWarning]="shouldShowWarning$ | async"
11+
[id]="flag.id"
1112
></app-common-section-card-title-header>
1213

1314
<!-- header-right -->

frontend/projects/upgrade/src/app/features/dashboard/feature-flags/pages/feature-flag-root-page/feature-flag-root-page-content/feature-flag-root-section-card/feature-flag-root-section-card.component.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ export class FeatureFlagRootSectionCardComponent {
5959
featureFlagFilterOption = [
6060
FLAG_SEARCH_KEY.ALL,
6161
FLAG_SEARCH_KEY.NAME,
62+
FLAG_SEARCH_KEY.ID,
6263
FLAG_SEARCH_KEY.STATUS,
6364
FLAG_SEARCH_KEY.CONTEXT,
6465
FLAG_SEARCH_KEY.TAG,

frontend/projects/upgrade/src/app/features/dashboard/home/components/experiment-list/experiment-list.component.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ export class ExperimentListComponent implements OnInit, OnDestroy, AfterViewInit
3333
experimentFilterOptions = [
3434
EXPERIMENT_SEARCH_KEY.ALL,
3535
EXPERIMENT_SEARCH_KEY.NAME,
36+
EXPERIMENT_SEARCH_KEY.ID,
3637
EXPERIMENT_SEARCH_KEY.STATUS,
3738
EXPERIMENT_SEARCH_KEY.TAG,
3839
EXPERIMENT_SEARCH_KEY.CONTEXT,
@@ -126,14 +127,17 @@ export class ExperimentListComponent implements OnInit, OnDestroy, AfterViewInit
126127
data.state.toLocaleLowerCase().includes(filter) ||
127128
!!data.tags.filter((tags) => tags.toLocaleLowerCase().includes(filter)).length ||
128129
this.isPartitionFound(data, filter) ||
129-
!!data.context.filter((context) => context.toLocaleLowerCase().includes(filter)).length
130+
!!data.context.filter((context) => context.toLocaleLowerCase().includes(filter)).length ||
131+
data.id.toLowerCase() === filter
130132
);
131133
case EXPERIMENT_SEARCH_KEY.NAME:
132134
return data.name.toLocaleLowerCase().includes(filter);
133135
case EXPERIMENT_SEARCH_KEY.TAG:
134136
return !!data.tags.filter((tags) => tags.toLocaleLowerCase().includes(filter)).length;
135137
case EXPERIMENT_SEARCH_KEY.CONTEXT:
136138
return !!data.context.filter((context) => context.toLocaleLowerCase().includes(filter)).length;
139+
case EXPERIMENT_SEARCH_KEY.ID:
140+
return data.id.toLowerCase() === filter;
137141
}
138142
};
139143
}

frontend/projects/upgrade/src/app/features/dashboard/home/pages/view-experiment/view-experiment.component.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@
6666
('home.view-experiment.updated-at.text' | translate) + (experiment.updatedAt | date : 'MMM d, y, h:mm a')
6767
}}
6868
</span>
69+
<span class="ft-14-700">ID: {{ experiment.id }}</span>
6970
</span>
7071

7172
<!-- <div class="action-buttons">

0 commit comments

Comments
 (0)