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;