mirror of
https://github.com/Unleash/unleash.git
synced 2025-01-25 00:07:47 +01:00
feat: return latest project events (#8287)
This commit is contained in:
parent
ed4c05d3c4
commit
e540db4cb3
@ -7,7 +7,7 @@ import {
|
|||||||
} from '../types';
|
} from '../types';
|
||||||
import { EVENT_MAP } from './feature-event-formatter-md-events';
|
import { EVENT_MAP } from './feature-event-formatter-md-events';
|
||||||
|
|
||||||
interface IFormattedEventData {
|
export interface IFormattedEventData {
|
||||||
label: string;
|
label: string;
|
||||||
text: string;
|
text: string;
|
||||||
url?: string;
|
url?: string;
|
||||||
|
@ -7,6 +7,9 @@ import { ProjectOwnersReadModel } from '../project/project-owners-read-model';
|
|||||||
import { FakeProjectOwnersReadModel } from '../project/fake-project-owners-read-model';
|
import { FakeProjectOwnersReadModel } from '../project/fake-project-owners-read-model';
|
||||||
import { ProjectReadModel } from '../project/project-read-model';
|
import { ProjectReadModel } from '../project/project-read-model';
|
||||||
import { FakeProjectReadModel } from '../project/fake-project-read-model';
|
import { FakeProjectReadModel } from '../project/fake-project-read-model';
|
||||||
|
import EventStore from '../../db/event-store';
|
||||||
|
import { FeatureEventFormatterMd } from '../../addons/feature-event-formatter-md';
|
||||||
|
import FakeEventStore from '../../../test/fixtures/fake-event-store';
|
||||||
|
|
||||||
export const createPersonalDashboardService = (
|
export const createPersonalDashboardService = (
|
||||||
db: Db,
|
db: Db,
|
||||||
@ -16,13 +19,23 @@ export const createPersonalDashboardService = (
|
|||||||
new PersonalDashboardReadModel(db),
|
new PersonalDashboardReadModel(db),
|
||||||
new ProjectOwnersReadModel(db),
|
new ProjectOwnersReadModel(db),
|
||||||
new ProjectReadModel(db, config.eventBus, config.flagResolver),
|
new ProjectReadModel(db, config.eventBus, config.flagResolver),
|
||||||
|
new EventStore(db, config.getLogger),
|
||||||
|
new FeatureEventFormatterMd({
|
||||||
|
unleashUrl: config.server.unleashUrl,
|
||||||
|
formatStyle: 'markdown',
|
||||||
|
}),
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const createFakePersonalDashboardService = () => {
|
export const createFakePersonalDashboardService = (config: IUnleashConfig) => {
|
||||||
return new PersonalDashboardService(
|
return new PersonalDashboardService(
|
||||||
new FakePersonalDashboardReadModel(),
|
new FakePersonalDashboardReadModel(),
|
||||||
new FakeProjectOwnersReadModel(),
|
new FakeProjectOwnersReadModel(),
|
||||||
new FakeProjectReadModel(),
|
new FakeProjectReadModel(),
|
||||||
|
new FakeEventStore(),
|
||||||
|
new FeatureEventFormatterMd({
|
||||||
|
unleashUrl: config.server.unleashUrl,
|
||||||
|
formatStyle: 'markdown',
|
||||||
|
}),
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -40,6 +40,7 @@ afterAll(async () => {
|
|||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
await db.stores.featureToggleStore.deleteAll();
|
await db.stores.featureToggleStore.deleteAll();
|
||||||
await db.stores.userStore.deleteAll();
|
await db.stores.userStore.deleteAll();
|
||||||
|
await db.stores.eventStore.deleteAll();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should return personal dashboard with own flags and favorited flags', async () => {
|
test('should return personal dashboard with own flags and favorited flags', async () => {
|
||||||
@ -178,6 +179,11 @@ test('should return projects where users are part of a group', async () => {
|
|||||||
|
|
||||||
test('should return personal dashboard project details', async () => {
|
test('should return personal dashboard project details', async () => {
|
||||||
await loginUser('new_user@test.com');
|
await loginUser('new_user@test.com');
|
||||||
|
|
||||||
|
await app.createFeature('log_feature_a');
|
||||||
|
await app.createFeature('log_feature_b');
|
||||||
|
await app.createFeature('log_feature_c');
|
||||||
|
|
||||||
const { body } = await app.request.get(
|
const { body } = await app.request.get(
|
||||||
`/api/admin/personal-dashboard/default`,
|
`/api/admin/personal-dashboard/default`,
|
||||||
);
|
);
|
||||||
@ -185,5 +191,29 @@ test('should return personal dashboard project details', async () => {
|
|||||||
expect(body).toMatchObject({
|
expect(body).toMatchObject({
|
||||||
owners: [{}],
|
owners: [{}],
|
||||||
roles: [{}],
|
roles: [{}],
|
||||||
|
latestEvents: [
|
||||||
|
{
|
||||||
|
createdBy: 'new_user@test.com',
|
||||||
|
summary: expect.stringContaining(
|
||||||
|
'**new_user@test.com** created **[log_feature_c]',
|
||||||
|
),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
createdBy: 'new_user@test.com',
|
||||||
|
summary: expect.stringContaining(
|
||||||
|
'**new_user@test.com** created **[log_feature_b]',
|
||||||
|
),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
createdBy: 'new_user@test.com',
|
||||||
|
summary: expect.stringContaining(
|
||||||
|
'**new_user@test.com** created **[log_feature_a]',
|
||||||
|
),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
createdBy: 'unleash_system_user',
|
||||||
|
summary: '**unleash_system_user** created user ****',
|
||||||
|
},
|
||||||
|
],
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -104,11 +104,17 @@ export default class PersonalDashboardController extends Controller {
|
|||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
const user = req.user;
|
const user = req.user;
|
||||||
|
|
||||||
|
const projectDetails =
|
||||||
|
await this.personalDashboardService.getPersonalProjectDetails(
|
||||||
|
req.params.projectId,
|
||||||
|
);
|
||||||
|
|
||||||
this.openApiService.respondWithValidation(
|
this.openApiService.respondWithValidation(
|
||||||
200,
|
200,
|
||||||
res,
|
res,
|
||||||
personalDashboardProjectDetailsSchema.$id,
|
personalDashboardProjectDetailsSchema.$id,
|
||||||
{
|
{
|
||||||
|
...projectDetails,
|
||||||
owners: [{ ownerType: 'user', name: 'placeholder' }],
|
owners: [{ ownerType: 'user', name: 'placeholder' }],
|
||||||
roles: [{ name: 'placeholder', id: 0, type: 'project' }],
|
roles: [{ name: 'placeholder', id: 0, type: 'project' }],
|
||||||
},
|
},
|
||||||
|
@ -5,6 +5,12 @@ import type {
|
|||||||
PersonalProject,
|
PersonalProject,
|
||||||
} from './personal-dashboard-read-model-type';
|
} from './personal-dashboard-read-model-type';
|
||||||
import type { IProjectReadModel } from '../project/project-read-model-type';
|
import type { IProjectReadModel } from '../project/project-read-model-type';
|
||||||
|
import type { IEventStore } from '../../types';
|
||||||
|
import type { FeatureEventFormatter } from '../../addons/feature-event-formatter-md';
|
||||||
|
|
||||||
|
type PersonalProjectDetails = {
|
||||||
|
latestEvents: { summary: string; createdBy: string }[];
|
||||||
|
};
|
||||||
|
|
||||||
export class PersonalDashboardService {
|
export class PersonalDashboardService {
|
||||||
private personalDashboardReadModel: IPersonalDashboardReadModel;
|
private personalDashboardReadModel: IPersonalDashboardReadModel;
|
||||||
@ -13,14 +19,22 @@ export class PersonalDashboardService {
|
|||||||
|
|
||||||
private projectReadModel: IProjectReadModel;
|
private projectReadModel: IProjectReadModel;
|
||||||
|
|
||||||
|
private eventStore: IEventStore;
|
||||||
|
|
||||||
|
private featureEventFormatter: FeatureEventFormatter;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
personalDashboardReadModel: IPersonalDashboardReadModel,
|
personalDashboardReadModel: IPersonalDashboardReadModel,
|
||||||
projectOwnersReadModel: IProjectOwnersReadModel,
|
projectOwnersReadModel: IProjectOwnersReadModel,
|
||||||
projectReadModel: IProjectReadModel,
|
projectReadModel: IProjectReadModel,
|
||||||
|
eventStore: IEventStore,
|
||||||
|
featureEventFormatter: FeatureEventFormatter,
|
||||||
) {
|
) {
|
||||||
this.personalDashboardReadModel = personalDashboardReadModel;
|
this.personalDashboardReadModel = personalDashboardReadModel;
|
||||||
this.projectOwnersReadModel = projectOwnersReadModel;
|
this.projectOwnersReadModel = projectOwnersReadModel;
|
||||||
this.projectReadModel = projectReadModel;
|
this.projectReadModel = projectReadModel;
|
||||||
|
this.eventStore = eventStore;
|
||||||
|
this.featureEventFormatter = featureEventFormatter;
|
||||||
}
|
}
|
||||||
|
|
||||||
getPersonalFeatures(userId: number): Promise<PersonalFeature[]> {
|
getPersonalFeatures(userId: number): Promise<PersonalFeature[]> {
|
||||||
@ -46,4 +60,20 @@ export class PersonalDashboardService {
|
|||||||
|
|
||||||
return normalizedProjects;
|
return normalizedProjects;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async getPersonalProjectDetails(
|
||||||
|
projectId: string,
|
||||||
|
): Promise<PersonalProjectDetails> {
|
||||||
|
const recentEvents = await this.eventStore.searchEvents(
|
||||||
|
{ project: projectId, limit: 4, offset: 0 },
|
||||||
|
[],
|
||||||
|
);
|
||||||
|
|
||||||
|
const formattedEvents = recentEvents.map((event) => ({
|
||||||
|
summary: this.featureEventFormatter.format(event).text,
|
||||||
|
createdBy: event.createdBy,
|
||||||
|
}));
|
||||||
|
|
||||||
|
return { latestEvents: formattedEvents };
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,6 +8,29 @@ export const personalDashboardProjectDetailsSchema = {
|
|||||||
additionalProperties: false,
|
additionalProperties: false,
|
||||||
required: ['owners', 'roles'],
|
required: ['owners', 'roles'],
|
||||||
properties: {
|
properties: {
|
||||||
|
latestEvents: {
|
||||||
|
type: 'array',
|
||||||
|
description: 'The latest events for the project.',
|
||||||
|
items: {
|
||||||
|
type: 'object',
|
||||||
|
description: 'An event summary',
|
||||||
|
additionalProperties: false,
|
||||||
|
required: ['summary', 'createdBy'],
|
||||||
|
properties: {
|
||||||
|
summary: {
|
||||||
|
type: 'string',
|
||||||
|
nullable: true,
|
||||||
|
description:
|
||||||
|
'**[Experimental]** A markdown-formatted summary of the event.',
|
||||||
|
},
|
||||||
|
createdBy: {
|
||||||
|
type: 'string',
|
||||||
|
description: 'Which user created this event',
|
||||||
|
example: 'johndoe',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
owners: projectSchema.properties.owners,
|
owners: projectSchema.properties.owners,
|
||||||
roles: {
|
roles: {
|
||||||
type: 'array',
|
type: 'array',
|
||||||
|
@ -408,7 +408,7 @@ export const createServices = (
|
|||||||
|
|
||||||
const personalDashboardService = db
|
const personalDashboardService = db
|
||||||
? createPersonalDashboardService(db, config)
|
? createPersonalDashboardService(db, config)
|
||||||
: createFakePersonalDashboardService();
|
: createFakePersonalDashboardService(config);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
accessService,
|
accessService,
|
||||||
|
Loading…
Reference in New Issue
Block a user