1
0
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:
Mateusz Kwasniewski 2024-09-27 12:47:21 +02:00 committed by GitHub
parent ed4c05d3c4
commit e540db4cb3
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 105 additions and 3 deletions

View File

@ -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;

View File

@ -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',
}),
); );
}; };

View File

@ -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 ****',
},
],
}); });
}); });

View File

@ -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' }],
}, },

View File

@ -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 };
}
} }

View File

@ -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',

View File

@ -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,