diff --git a/frontend/src/component/events/EventCard/EventCard.tsx b/frontend/src/component/events/EventCard/EventCard.tsx index 60d6cf0be3..a8ef81caa1 100644 --- a/frontend/src/component/events/EventCard/EventCard.tsx +++ b/frontend/src/component/events/EventCard/EventCard.tsx @@ -89,6 +89,12 @@ const EventCard = ({ entry }: IEventCardProps) => {
{entry.type}
Changed by:
{entry.createdBy}
+ {entry.ip && ( + <> + IP: +
{entry.ip}
+ + )} , - { getLogger, eventBus }: Pick, + { + getLogger, + eventBus, + isEnterprise, + }: Pick, privateProjectChecker: IPrivateProjectChecker, accessReadModel: IAccessReadModel, ) { @@ -46,6 +52,7 @@ export default class EventService { this.privateProjectChecker = privateProjectChecker; this.featureTagStore = featureTagStore; this.eventBus = eventBus; + this.isEnterprise = isEnterprise; this.accessReadModel = accessReadModel; } @@ -101,6 +108,9 @@ export default class EventService { query: search.query, }, queryParams, + { + withIp: this.isEnterprise, + }, ); return { events, diff --git a/src/lib/features/events/event-store.ts b/src/lib/features/events/event-store.ts index 76dab46467..4241e86229 100644 --- a/src/lib/features/events/event-store.ts +++ b/src/lib/features/events/event-store.ts @@ -93,6 +93,7 @@ export interface IEventTable { project?: string; environment?: string; tags: ITag[]; + ip?: string; } const TABLE = 'events'; @@ -374,15 +375,20 @@ class EventStore implements IEventStore { async searchEvents( params: IEventSearchParams, queryParams: IQueryParam[], + options?: { withIp?: boolean }, ): Promise { const query = this.buildSearchQuery(params, queryParams) - .select(EVENT_COLUMNS) + .select(options?.withIp ? [...EVENT_COLUMNS, 'ip'] : EVENT_COLUMNS) .orderBy('created_at', 'desc') .limit(Number(params.limit) ?? 100) .offset(Number(params.offset) ?? 0); try { - return (await query).map(this.rowToEvent); + return (await query).map((row) => + options?.withIp + ? { ...this.rowToEvent(row), ip: row.ip } + : this.rowToEvent(row), + ); } catch (err) { return []; } diff --git a/src/lib/openapi/spec/event-schema.ts b/src/lib/openapi/spec/event-schema.ts index fe33fbe732..88dcbf1cbc 100644 --- a/src/lib/openapi/spec/event-schema.ts +++ b/src/lib/openapi/spec/event-schema.ts @@ -102,6 +102,13 @@ export const eventSchema = { nullable: true, description: 'A markdown-formatted summary of the event.', }, + ip: { + type: 'string', + nullable: true, + description: + 'The IP address of the user that created the event. Only available in Enterprise.', + example: '192.168.1.1', + }, }, components: { schemas: { diff --git a/src/lib/types/events.ts b/src/lib/types/events.ts index b4b6d28fa8..ac8d181126 100644 --- a/src/lib/types/events.ts +++ b/src/lib/types/events.ts @@ -400,6 +400,7 @@ export interface IBaseEvent { export interface IEvent extends Omit { id: number; createdAt: Date; + ip?: string; } export interface IEnrichedEvent extends IEvent { diff --git a/src/lib/types/stores/event-store.ts b/src/lib/types/stores/event-store.ts index 93cc7d8a21..2f66a41c39 100644 --- a/src/lib/types/stores/event-store.ts +++ b/src/lib/types/stores/event-store.ts @@ -41,6 +41,7 @@ export interface IEventStore searchEvents( params: IEventSearchParams, queryParams: IQueryParam[], + options?: { withIp?: boolean }, ): Promise; getMaxRevisionId(currentMax?: number): Promise; getRevisionRange(start: number, end: number): Promise;