Skip to content

Commit

Permalink
feat: archived features can be searched now (#8568)
Browse files Browse the repository at this point in the history
Archived features can be searched now.
This is the backend and small parts of frontend preparing to add
filters, buttons etc in next PR.

---------

Co-authored-by: Thomas Heartman <[email protected]>
  • Loading branch information
sjaanus and thomasheartman authored Oct 29, 2024
1 parent 30c14ff commit 28e062b
Show file tree
Hide file tree
Showing 7 changed files with 62 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ export const ProjectFeatureToggles = ({
type: tableState.type,
state: tableState.state,
createdBy: tableState.createdBy,
archived: tableState.archived,
};

const { favorite, unfavorite } = useFavoriteFeaturesApi();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ export const useProjectFeatureSearch = (
createdAt: FilterItemParam,
type: FilterItemParam,
createdBy: FilterItemParam,
archived: FilterItemParam,
};
const [tableState, setTableState] = usePersistentTableState(
`${storageKey}-${projectId}`,
Expand Down
3 changes: 3 additions & 0 deletions src/lib/features/feature-search/feature-search-controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ export default class FeatureSearchController extends Controller {
state,
status,
favoritesFirst,
archived,
sortBy,
} = req.query;
const userId = req.user.id;
Expand Down Expand Up @@ -131,6 +132,7 @@ export default class FeatureSearchController extends Controller {
['enabled', 'disabled'].includes(tag[1]),
);
const normalizedFavoritesFirst = favoritesFirst === 'true';
const normalizedArchived = archived === 'IS:true';
const { features, total } = await this.featureSearchService.search({
searchParams: normalizedQuery,
project,
Expand All @@ -147,6 +149,7 @@ export default class FeatureSearchController extends Controller {
limit: normalizedLimit,
sortOrder: normalizedSortOrder,
favoritesFirst: normalizedFavoritesFirst,
archived: normalizedArchived,
});

this.openApiService.respondWithValidation(
Expand Down
4 changes: 2 additions & 2 deletions src/lib/features/feature-search/feature-search-store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ class FeatureSearchStore implements IFeatureSearchStore {
limit,
sortOrder,
sortBy,
archived,
favoritesFirst,
}: IFeatureSearchParams,
queryParams: IQueryParam[],
Expand Down Expand Up @@ -188,9 +189,8 @@ class FeatureSearchStore implements IFeatureSearchStore {
}
});
}

query
.modify(FeatureToggleStore.filterByArchived, false)
.modify(FeatureToggleStore.filterByArchived, archived)
.leftJoin(
'feature_environments',
'feature_environments.feature_name',
Expand Down
46 changes: 44 additions & 2 deletions src/lib/features/feature-search/feature.search.e2e.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,16 +57,23 @@ afterAll(async () => {
});

beforeEach(async () => {
await db.stores.dependentFeaturesStore.deleteAll();
await db.stores.featureToggleStore.deleteAll();
await db.stores.segmentStore.deleteAll();
});

const searchFeatures = async (
{ query = '', project = 'IS:default' }: FeatureSearchQueryParameters,
{
query = '',
project = 'IS:default',
archived = 'IS:false',
}: FeatureSearchQueryParameters,
expectedCode = 200,
) => {
return app.request
.get(`/api/admin/search/features?query=${query}&project=${project}`)
.get(
`/api/admin/search/features?query=${query}&project=${project}&archived=${archived}`,
)
.expect(expectedCode);
};

Expand Down Expand Up @@ -1128,3 +1135,38 @@ test('should return dependencyType', async () => {
],
});
});

test('should return archived when query param set', async () => {
await app.createFeature({
name: 'my_feature_a',
createdAt: '2023-01-29T15:21:39.975Z',
});
await app.createFeature({
name: 'my_feature_b',
createdAt: '2023-01-29T15:21:39.975Z',
archived: true,
});

const { body } = await searchFeatures({
query: 'my_feature',
});
expect(body).toMatchObject({
features: [
{
name: 'my_feature_a',
},
],
});

const { body: archivedFeatures } = await searchFeatures({
query: 'my_feature',
archived: 'IS:true',
});
expect(archivedFeatures).toMatchObject({
features: [
{
name: 'my_feature_b',
},
],
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ export interface IFeatureSearchParams {
status?: string[][];
offset: number;
favoritesFirst?: boolean;
archived?: boolean;
limit: number;
sortBy?: string;
sortOrder: 'asc' | 'desc';
Expand Down
10 changes: 10 additions & 0 deletions src/lib/openapi/spec/feature-search-query-parameters.ts
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,16 @@ export const featureSearchQueryParameters = [
'The flag to indicate if the favorite features should be returned first. By default it is set to false.',
in: 'query',
},
{
name: 'archived',
schema: {
type: 'string',
example: 'IS:true',
},
description:
'Whether to get results for archived feature flags or active feature flags. If `true`, Unleash will return only archived flags. If `false`, it will return only active flags.',
in: 'query',
},
{
name: 'createdAt',
schema: {
Expand Down

0 comments on commit 28e062b

Please sign in to comment.