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,
|
yes: Number(r.yes) || 0,
|
||||||
no: Number(r.no) || 0,
|
no: Number(r.no) || 0,
|
||||||
changeRequestIds: r.change_request_ids ?? [],
|
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');
|
.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);
|
this.queryExtraData(finalQuery);
|
||||||
const rows = await 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:
|
description:
|
||||||
'Experimental. A list of change request identifiers for actionable change requests that are not Cancelled, Rejected or Approved.',
|
'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: {
|
lastSeenAt: {
|
||||||
type: 'string',
|
type: 'string',
|
||||||
format: 'date-time',
|
format: 'date-time',
|
||||||
|
@ -60,6 +60,7 @@ process.nextTick(async () => {
|
|||||||
tagTypeColor: true,
|
tagTypeColor: true,
|
||||||
newStrategyDropdown: true,
|
newStrategyDropdown: true,
|
||||||
addEditStrategy: true,
|
addEditStrategy: true,
|
||||||
|
flagsOverviewSearch: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
authentication: {
|
authentication: {
|
||||||
|
Loading…
Reference in New Issue
Block a user