mirror of
https://github.com/Unleash/unleash.git
synced 2025-07-21 13:47:39 +02:00
feat: total count respect lifecycle filter (#9724)
This commit is contained in:
parent
827b8f274a
commit
e876e6438d
@ -79,24 +79,6 @@ class FeatureSearchStore implements IFeatureSearchStore {
|
||||
};
|
||||
}
|
||||
|
||||
private getLatestLifecycleStageQuery() {
|
||||
return this.db('feature_lifecycles')
|
||||
.select(
|
||||
'feature as stage_feature',
|
||||
'stage as latest_stage',
|
||||
'status as stage_status',
|
||||
'created_at as entered_stage_at',
|
||||
)
|
||||
.distinctOn('stage_feature')
|
||||
.orderBy([
|
||||
'stage_feature',
|
||||
{
|
||||
column: 'entered_stage_at',
|
||||
order: 'desc',
|
||||
},
|
||||
]);
|
||||
}
|
||||
|
||||
async searchFeatures(
|
||||
{
|
||||
userId,
|
||||
@ -147,6 +129,9 @@ class FeatureSearchStore implements IFeatureSearchStore {
|
||||
'users.username as user_username',
|
||||
'users.email as user_email',
|
||||
'users.image_url as user_image_url',
|
||||
'lifecycle.latest_stage',
|
||||
'lifecycle.stage_status',
|
||||
'lifecycle.entered_stage_at',
|
||||
] as (string | Raw<any> | Knex.QueryBuilder)[];
|
||||
|
||||
const lastSeenQuery = 'last_seen_at_metrics.last_seen_at';
|
||||
@ -245,19 +230,48 @@ class FeatureSearchStore implements IFeatureSearchStore {
|
||||
'users',
|
||||
'users.id',
|
||||
'features.created_by_user_id',
|
||||
)
|
||||
.leftJoin('last_seen_at_metrics', function () {
|
||||
this.on(
|
||||
'last_seen_at_metrics.environment',
|
||||
'=',
|
||||
'environments.name',
|
||||
).andOn(
|
||||
'last_seen_at_metrics.feature_name',
|
||||
'=',
|
||||
'features.name',
|
||||
);
|
||||
})
|
||||
.leftJoin(
|
||||
this.db
|
||||
.select(
|
||||
'feature as stage_feature',
|
||||
'stage as latest_stage',
|
||||
'status as stage_status',
|
||||
'created_at as entered_stage_at',
|
||||
)
|
||||
.from('feature_lifecycles')
|
||||
.distinctOn('feature')
|
||||
.orderBy([
|
||||
'feature',
|
||||
{ column: 'created_at', order: 'desc' },
|
||||
])
|
||||
.as('lifecycle'),
|
||||
'features.name',
|
||||
'lifecycle.stage_feature',
|
||||
);
|
||||
|
||||
query.leftJoin('last_seen_at_metrics', function () {
|
||||
this.on(
|
||||
'last_seen_at_metrics.environment',
|
||||
'=',
|
||||
'environments.name',
|
||||
).andOn(
|
||||
'last_seen_at_metrics.feature_name',
|
||||
'=',
|
||||
'features.name',
|
||||
);
|
||||
});
|
||||
if (this.flagResolver.isEnabled('flagsOverviewSearch')) {
|
||||
const parsedLifecycle = lifecycle
|
||||
? parseSearchOperatorValue(
|
||||
'lifecycle.latest_stage',
|
||||
lifecycle,
|
||||
)
|
||||
: null;
|
||||
if (parsedLifecycle) {
|
||||
applyGenericQueryParams(query, [parsedLifecycle]);
|
||||
}
|
||||
}
|
||||
|
||||
const rankingSql = this.buildRankingSql(
|
||||
favoritesFirst,
|
||||
@ -270,7 +284,6 @@ class FeatureSearchStore implements IFeatureSearchStore {
|
||||
.select(selectColumns)
|
||||
.denseRank('rank', this.db.raw(rankingSql));
|
||||
})
|
||||
.with('lifecycle', this.getLatestLifecycleStageQuery())
|
||||
.with(
|
||||
'final_ranks',
|
||||
this.db.raw(
|
||||
@ -321,26 +334,8 @@ class FeatureSearchStore implements IFeatureSearchStore {
|
||||
.joinRaw('CROSS JOIN total_features')
|
||||
.whereBetween('final_rank', [offset + 1, offset + limit])
|
||||
.orderBy('final_rank');
|
||||
finalQuery
|
||||
.select(
|
||||
'lifecycle.latest_stage',
|
||||
'lifecycle.stage_status',
|
||||
'lifecycle.entered_stage_at',
|
||||
)
|
||||
.leftJoin(
|
||||
'lifecycle',
|
||||
'ranked_features.feature_name',
|
||||
'lifecycle.stage_feature',
|
||||
);
|
||||
|
||||
if (this.flagResolver.isEnabled('flagsOverviewSearch')) {
|
||||
const parsedLifecycle = lifecycle
|
||||
? parseSearchOperatorValue('lifecycle.latest_stage', lifecycle)
|
||||
: null;
|
||||
if (parsedLifecycle) {
|
||||
applyGenericQueryParams(finalQuery, [parsedLifecycle]);
|
||||
}
|
||||
|
||||
finalQuery
|
||||
.leftJoin(
|
||||
this.db('change_request_events AS cre')
|
||||
|
@ -1111,6 +1111,10 @@ test('should return environment usage metrics and lifecycle', async () => {
|
||||
name: 'my_feature_b',
|
||||
createdAt: '2023-01-29T15:21:39.975Z',
|
||||
});
|
||||
await app.createFeature({
|
||||
name: 'my_feature_c',
|
||||
createdAt: '2023-01-29T15:21:39.975Z',
|
||||
});
|
||||
|
||||
await stores.clientMetricsStoreV2.batchInsertMetrics([
|
||||
{
|
||||
@ -1142,6 +1146,9 @@ test('should return environment usage metrics and lifecycle', async () => {
|
||||
await stores.featureLifecycleStore.insert([
|
||||
{ feature: 'my_feature_b', stage: 'initial' },
|
||||
]);
|
||||
await stores.featureLifecycleStore.insert([
|
||||
{ feature: 'my_feature_c', stage: 'initial' },
|
||||
]);
|
||||
await stores.featureLifecycleStore.insert([
|
||||
{ feature: 'my_feature_b', stage: 'completed', status: 'discarded' },
|
||||
]);
|
||||
@ -1150,6 +1157,7 @@ test('should return environment usage metrics and lifecycle', async () => {
|
||||
query: 'my_feature_b',
|
||||
});
|
||||
expect(noExplicitLifecycle).toMatchObject({
|
||||
total: 1,
|
||||
features: [
|
||||
{
|
||||
name: 'my_feature_b',
|
||||
@ -1180,14 +1188,17 @@ test('should return environment usage metrics and lifecycle', async () => {
|
||||
query: 'my_feature_b',
|
||||
lifecycle: 'IS:initial',
|
||||
});
|
||||
expect(noFeaturesWithOtherLifecycle).toMatchObject({ features: [] });
|
||||
expect(noFeaturesWithOtherLifecycle).toMatchObject({
|
||||
total: 0,
|
||||
features: [],
|
||||
});
|
||||
|
||||
const { body: featureWithMatchingLifecycle } =
|
||||
await searchFeaturesWithLifecycle({
|
||||
query: 'my_feature_b',
|
||||
lifecycle: 'IS:completed',
|
||||
});
|
||||
expect(featureWithMatchingLifecycle).toMatchObject({
|
||||
total: 1,
|
||||
features: [{ name: 'my_feature_b' }],
|
||||
});
|
||||
});
|
||||
|
Loading…
Reference in New Issue
Block a user