mirror of
https://github.com/Unleash/unleash.git
synced 2025-01-20 00:08:02 +01:00
feat: application missing features backend (#6330)
This PR adds a property issues to application schema, and also adds all the missing features that have been reported by SDK, but do not exist in Unleash.
This commit is contained in:
parent
d1e93228a3
commit
89d113f1ff
@ -10,6 +10,7 @@ import { Logger, LogProvider } from '../logger';
|
||||
import { Db } from './db';
|
||||
import { IApplicationOverview } from '../features/metrics/instance/models';
|
||||
import { applySearchFilters } from '../features/feature-search/search-utils';
|
||||
import { ApplicationOverviewIssuesSchema } from '../openapi/spec/application-overview-issues-schema';
|
||||
|
||||
const COLUMNS = [
|
||||
'app_name',
|
||||
@ -305,7 +306,6 @@ export default class ClientApplicationsStore
|
||||
);
|
||||
})
|
||||
.where('a.app_name', appName);
|
||||
|
||||
const rows = await query;
|
||||
if (!rows.length) {
|
||||
throw new NotFoundError(`Could not find appName=${appName}`);
|
||||
@ -316,22 +316,41 @@ export default class ClientApplicationsStore
|
||||
|
||||
mapApplicationOverviewData(rows: any[]): IApplicationOverview {
|
||||
const featureCount = new Set(rows.map((row) => row.feature_name)).size;
|
||||
const missingFeatures: Set<string> = new Set();
|
||||
|
||||
const environments = rows.reduce((acc, row) => {
|
||||
const { environment, instance_id, sdk_version, last_seen } = row;
|
||||
const {
|
||||
environment,
|
||||
instance_id,
|
||||
sdk_version,
|
||||
last_seen,
|
||||
project,
|
||||
feature_name,
|
||||
} = row;
|
||||
|
||||
if (!environment) return acc;
|
||||
|
||||
if (!project && feature_name) {
|
||||
missingFeatures.add(feature_name);
|
||||
}
|
||||
|
||||
let env = acc.find((e) => e.name === environment);
|
||||
if (!env) {
|
||||
env = {
|
||||
name: environment,
|
||||
instanceCount: 1,
|
||||
instanceCount: instance_id ? 1 : 0,
|
||||
sdks: sdk_version ? [sdk_version] : [],
|
||||
lastSeen: last_seen,
|
||||
uniqueInstanceIds: new Set([instance_id]),
|
||||
uniqueInstanceIds: new Set(
|
||||
instance_id ? [instance_id] : [],
|
||||
),
|
||||
};
|
||||
acc.push(env);
|
||||
} else {
|
||||
env.uniqueInstanceIds.add(instance_id);
|
||||
env.instanceCount = env.uniqueInstanceIds.size;
|
||||
if (instance_id && !env.uniqueInstanceIds.has(instance_id)) {
|
||||
env.uniqueInstanceIds.add(instance_id);
|
||||
env.instanceCount = env.uniqueInstanceIds.size;
|
||||
}
|
||||
if (sdk_version && !env.sdks.includes(sdk_version)) {
|
||||
env.sdks.push(sdk_version);
|
||||
}
|
||||
@ -342,12 +361,21 @@ export default class ClientApplicationsStore
|
||||
|
||||
return acc;
|
||||
}, []);
|
||||
|
||||
environments.forEach((env) => {
|
||||
delete env.uniqueInstanceIds;
|
||||
env.sdks.sort();
|
||||
});
|
||||
|
||||
const issues: ApplicationOverviewIssuesSchema[] =
|
||||
missingFeatures.size > 0
|
||||
? [
|
||||
{
|
||||
type: 'missingFeatures',
|
||||
items: [...missingFeatures],
|
||||
},
|
||||
]
|
||||
: [];
|
||||
|
||||
return {
|
||||
projects: [
|
||||
...new Set(
|
||||
@ -358,6 +386,7 @@ export default class ClientApplicationsStore
|
||||
],
|
||||
featureCount,
|
||||
environments,
|
||||
issues,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -9,7 +9,7 @@ export const applicationOverviewIssuesSchema = {
|
||||
properties: {
|
||||
type: {
|
||||
type: 'string',
|
||||
enum: ['missingFeature', 'missingStrategy'],
|
||||
enum: ['missingFeatures', 'missingStrategies'],
|
||||
description: 'The name of this action.',
|
||||
},
|
||||
items: {
|
||||
|
@ -5,8 +5,8 @@ test('applicationOverviewSchema', () => {
|
||||
projects: ['default', 'dx'],
|
||||
featureCount: 12,
|
||||
issues: [
|
||||
{ type: 'missingFeature', items: ['feature1'] },
|
||||
{ type: 'missingStrategy', items: ['strategy1'] },
|
||||
{ type: 'missingFeatures', items: ['feature1'] },
|
||||
{ type: 'missingStrategies', items: ['strategy1'] },
|
||||
],
|
||||
environments: [
|
||||
{
|
||||
|
@ -8,7 +8,7 @@ export const applicationOverviewSchema = {
|
||||
description:
|
||||
"Data about an application that's connected to Unleash via an SDK.",
|
||||
additionalProperties: false,
|
||||
required: ['projects', 'featureCount', 'environments'],
|
||||
required: ['projects', 'featureCount', 'environments', 'issues'],
|
||||
properties: {
|
||||
projects: {
|
||||
description: 'The list of projects the application has been using.',
|
||||
|
@ -122,6 +122,7 @@ test('should show correct number of total', async () => {
|
||||
|
||||
const expected = {
|
||||
projects: ['default'],
|
||||
issues: [],
|
||||
environments: [
|
||||
{
|
||||
instanceCount: 2,
|
||||
@ -134,3 +135,49 @@ test('should show correct number of total', async () => {
|
||||
|
||||
expect(body).toMatchObject(expected);
|
||||
});
|
||||
|
||||
test('should show missing features', async () => {
|
||||
await Promise.all([
|
||||
app.createFeature('toggle-name-1'),
|
||||
app.request.post('/api/client/register').send({
|
||||
appName: metrics.appName,
|
||||
instanceId: metrics.instanceId,
|
||||
strategies: ['default'],
|
||||
sdkVersion: 'unleash-client-test',
|
||||
started: Date.now(),
|
||||
interval: 10,
|
||||
}),
|
||||
]);
|
||||
await app.services.clientInstanceService.bulkAdd();
|
||||
await app.request
|
||||
.post('/api/client/metrics')
|
||||
.set('Authorization', defaultToken.secret)
|
||||
.send(metrics)
|
||||
.expect(202);
|
||||
|
||||
await app.services.clientMetricsServiceV2.bulkAdd();
|
||||
|
||||
const { body } = await app.request
|
||||
.get(`/api/admin/metrics/applications/${metrics.appName}/overview`)
|
||||
.expect(200);
|
||||
|
||||
const expected = {
|
||||
projects: ['default'],
|
||||
issues: [
|
||||
{
|
||||
type: 'missingFeatures',
|
||||
items: ['toggle-name-2', 'toggle-name-3'],
|
||||
},
|
||||
],
|
||||
environments: [
|
||||
{
|
||||
instanceCount: 1,
|
||||
name: 'default',
|
||||
sdks: ['unleash-client-test'],
|
||||
},
|
||||
],
|
||||
featureCount: 3,
|
||||
};
|
||||
|
||||
expect(body).toMatchObject(expected);
|
||||
});
|
||||
|
Loading…
Reference in New Issue
Block a user