1
0
mirror of https://github.com/Unleash/unleash.git synced 2025-07-26 13:48:33 +02:00

feat: add milestones to search results (#9739)

This commit is contained in:
Mateusz Kwasniewski 2025-04-10 10:25:39 +02:00 committed by GitHub
parent 49a1dac2c9
commit 8f117ac18e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 163 additions and 0 deletions

View File

@ -76,6 +76,13 @@ class FeatureSearchStore implements IFeatureSearchStore {
yes: Number(r.yes) || 0,
no: Number(r.no) || 0,
changeRequestIds: r.change_request_ids ?? [],
...(r.milestone_name
? {
milestoneName: r.milestone_name,
milestoneOrder: r.milestone_order,
totalMilestones: Number(r.total_milestones || 0),
}
: {}),
};
}
@ -371,6 +378,53 @@ class FeatureSearchStore implements IFeatureSearchStore {
},
)
.select('feature_cr.change_request_ids');
finalQuery
.leftJoin(
this.db
.with('total_milestones', (qb) => {
qb.select('release_plan_definition_id')
.count('* as total_milestones')
.from('milestones')
.groupBy('release_plan_definition_id');
})
.select([
'rpd.feature_name',
'rpd.environment',
'active_milestone.sort_order AS milestone_order',
'total_milestones.total_milestones',
'active_milestone.name AS milestone_name',
])
.from('release_plan_definitions AS rpd')
.join(
'total_milestones',
'total_milestones.release_plan_definition_id',
'rpd.id',
)
.join(
'milestones AS active_milestone',
'active_milestone.id',
'rpd.active_milestone_id',
)
.where('rpd.discriminator', 'plan')
.as('feature_release_plan'),
function () {
this.on(
'feature_release_plan.feature_name',
'=',
'ranked_features.feature_name',
).andOn(
'feature_release_plan.environment',
'=',
'ranked_features.environment',
);
},
)
.select([
'feature_release_plan.milestone_name',
'feature_release_plan.milestone_order',
'feature_release_plan.total_milestones',
]);
}
this.queryExtraData(finalQuery);
const rows = await finalQuery;

View File

@ -1425,3 +1425,93 @@ test('should return change request ids per environment', async () => {
],
});
});
const createReleasePlan = async ({
feature,
environment,
planId,
}: { feature: string; environment: string; planId: string }) => {
await db.rawDatabase('release_plan_definitions').insert({
id: planId,
discriminator: 'plan',
name: 'plan',
feature_name: feature,
environment: environment,
created_by_user_id: 1,
});
};
const createMilestone = async ({
id,
name,
order,
planId,
}: { id: string; name: string; order: number; planId: string }) => {
await db.rawDatabase('milestones').insert({
id,
name,
sort_order: order,
release_plan_definition_id: planId,
});
};
const activateMilestone = async ({
planId,
milestoneId,
}: { planId: string; milestoneId: string }) => {
await db
.rawDatabase('release_plan_definitions')
.update({ active_milestone_id: milestoneId })
.where('id', planId);
};
test('should return release plan milestones', async () => {
await app.createFeature('my_feature_a');
await createReleasePlan({
feature: 'my_feature_a',
environment: 'development',
planId: 'plan0',
});
await createMilestone({
id: 'milestone0',
name: 'Milestone 1',
order: 0,
planId: 'plan0',
});
await createMilestone({
id: 'milestone1',
name: 'Milestone 2',
order: 1,
planId: 'plan0',
});
await createMilestone({
id: 'milestone3',
name: 'Milestone 3',
order: 2,
planId: 'plan0',
});
await activateMilestone({ planId: 'plan0', milestoneId: 'milestone1' });
const { body } = await searchFeatures({});
expect(body).toMatchObject({
features: [
{
name: 'my_feature_a',
environments: [
{ name: 'default' },
{
name: 'development',
totalMilestones: 3,
milestoneName: 'Milestone 2',
milestoneOrder: 1,
},
{ name: 'production' },
],
},
],
});
expect(body.features[0].environments[0].milestoneName).toBeUndefined();
expect(body.features[0].environments[2].milestoneName).toBeUndefined();
});

View File

@ -71,6 +71,24 @@ export const featureEnvironmentSchema = {
description:
'Experimental. A list of change request identifiers for actionable change requests that are not Cancelled, Rejected or Approved.',
},
milestoneName: {
type: 'string',
example: 'Phase One',
description:
'Experimental: The name of the currently active release plan milestone',
},
milestoneOrder: {
type: 'number',
example: 0,
description:
'Experimental: The zero-indexed order of currently active milestone in the list of all release plan milestones',
},
totalMilestones: {
type: 'number',
example: 0,
description:
'Experimental: The total number of milestones in the feature environment release plan',
},
lastSeenAt: {
type: 'string',
format: 'date-time',

View File

@ -60,6 +60,7 @@ process.nextTick(async () => {
tagTypeColor: true,
newStrategyDropdown: true,
addEditStrategy: true,
flagsOverviewSearch: true,
},
},
authentication: {