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:
parent
49a1dac2c9
commit
8f117ac18e
@ -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;
|
||||
|
@ -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();
|
||||
});
|
||||
|
@ -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',
|
||||
|
@ -60,6 +60,7 @@ process.nextTick(async () => {
|
||||
tagTypeColor: true,
|
||||
newStrategyDropdown: true,
|
||||
addEditStrategy: true,
|
||||
flagsOverviewSearch: true,
|
||||
},
|
||||
},
|
||||
authentication: {
|
||||
|
Loading…
Reference in New Issue
Block a user