diff --git a/.changeset/lovely-shirts-play.md b/.changeset/lovely-shirts-play.md
new file mode 100644
index 0000000000000..3760e7c5c653e
--- /dev/null
+++ b/.changeset/lovely-shirts-play.md
@@ -0,0 +1,6 @@
+---
+'@rocket.chat/rest-typings': patch
+'@rocket.chat/meteor': patch
+---
+
+Fix an issue where the report exported in the App logs page would not consider the instance id filter
diff --git a/apps/meteor/client/views/marketplace/AppDetailsPage/tabs/AppLogs/Filters/ExportLogsModal.spec.tsx b/apps/meteor/client/views/marketplace/AppDetailsPage/tabs/AppLogs/Filters/ExportLogsModal.spec.tsx
index f7c84846694c0..f36881642a18a 100644
--- a/apps/meteor/client/views/marketplace/AppDetailsPage/tabs/AppLogs/Filters/ExportLogsModal.spec.tsx
+++ b/apps/meteor/client/views/marketplace/AppDetailsPage/tabs/AppLogs/Filters/ExportLogsModal.spec.tsx
@@ -10,6 +10,10 @@ const testCases = Object.values(composeStories(stories)).map((Story) => [Story.s
const onConfirm = jest.fn();
const { Default } = composeStories(stories);
+afterEach(() => {
+ jest.clearAllMocks();
+});
+
test.each(testCases)(`renders without crashing`, async (_storyname, Story) => {
const view = render(, {
wrapper: mockAppRoot().build(),
@@ -35,3 +39,22 @@ it('should send the correct payload to the endpoint', async () => {
expect(onConfirm).toHaveBeenCalledTimes(1);
expect(onConfirm).toHaveBeenCalledWith('/api/apps/undefined/export-logs?count=2000&type=json');
});
+
+it('should include instance filter in the payload to endpoint', async () => {
+ render(
+ ,
+ {
+ wrapper: mockAppRoot().build(),
+ },
+ );
+
+ expect(screen.getByRole('button', { name: 'Download' })).toBeInTheDocument();
+ await userEvent.click(screen.getByRole('button', { name: 'Download' }));
+ expect(onConfirm).toHaveBeenCalledTimes(1);
+ expect(onConfirm).toHaveBeenCalledWith('/api/apps/undefined/export-logs?instanceId=123&count=2000&type=json');
+});
diff --git a/apps/meteor/client/views/marketplace/AppDetailsPage/tabs/AppLogs/Filters/ExportLogsModal.tsx b/apps/meteor/client/views/marketplace/AppDetailsPage/tabs/AppLogs/Filters/ExportLogsModal.tsx
index 87b44b584af8c..0adece3e2d905 100644
--- a/apps/meteor/client/views/marketplace/AppDetailsPage/tabs/AppLogs/Filters/ExportLogsModal.tsx
+++ b/apps/meteor/client/views/marketplace/AppDetailsPage/tabs/AppLogs/Filters/ExportLogsModal.tsx
@@ -57,6 +57,7 @@ export const ExportLogsModal = ({ onClose, filterValues, onConfirm }: ExportLogs
const getFileUrl = ({
severity,
event,
+ instance,
startDate,
endDate,
count,
@@ -71,6 +72,9 @@ export const ExportLogsModal = ({ onClose, filterValues, onConfirm }: ExportLogs
if (event && event !== 'all') {
baseUrl += `method=${event}&`;
}
+ if (instance && instance !== 'all') {
+ baseUrl += `instanceId=${instance}&`;
+ }
if (startDate) {
baseUrl += `startDate=${new Date(`${startDate}T${startTime}`).toISOString()}&`;
}
diff --git a/apps/meteor/tests/data/api-data.ts b/apps/meteor/tests/data/api-data.ts
index 4b936d5c6558c..6bfb97756ec73 100644
--- a/apps/meteor/tests/data/api-data.ts
+++ b/apps/meteor/tests/data/api-data.ts
@@ -63,6 +63,8 @@ export function log(res: Response) {
});
}
+let instanceId: string | undefined;
+
export function getCredentials(done?: CallbackHandler) {
void request
.post(api('login'))
@@ -75,6 +77,11 @@ export function getCredentials(done?: CallbackHandler) {
.expect((res) => {
credentials['X-Auth-Token'] = res.body.data.authToken;
credentials['X-User-Id'] = res.body.data.userId;
+ instanceId = res.headers['x-instance-id'];
})
.end(done);
}
+
+export function getInstanceId() {
+ return instanceId;
+}
diff --git a/apps/meteor/tests/end-to-end/apps/app-logs-export.ts b/apps/meteor/tests/end-to-end/apps/app-logs-export.ts
index 59ed69ff591b4..0d8b1fc088a44 100644
--- a/apps/meteor/tests/end-to-end/apps/app-logs-export.ts
+++ b/apps/meteor/tests/end-to-end/apps/app-logs-export.ts
@@ -3,7 +3,7 @@ import type { App } from '@rocket.chat/core-typings';
import { expect } from 'chai';
import { after, before, describe, it } from 'mocha';
-import { getCredentials, request, credentials } from '../../data/api-data';
+import { getCredentials, request, credentials, getInstanceId } from '../../data/api-data';
import { apps } from '../../data/apps/apps-data';
import { installTestApp, cleanupApps } from '../../data/apps/helper';
import { IS_EE } from '../../e2e/config/constants';
@@ -168,6 +168,25 @@ import { IS_EE } from '../../e2e/config/constants';
.end(done);
});
+ it('should export app logs filtered by instance id', (done) => {
+ const instanceId = getInstanceId();
+ void request
+ .get(apps(`/${app.id}/export-logs`))
+ .query({ instanceId, type: 'json' })
+ .set(credentials)
+ .expect('Content-Type', 'text/plain')
+ .expect(200)
+ .expect((res) => {
+ const logs = JSON.parse(res.text);
+ expect(logs).to.be.an('array');
+
+ logs.forEach((log: ILoggerStorageEntry) => {
+ expect(log.instanceId).to.equal(instanceId);
+ });
+ })
+ .end(done);
+ });
+
it('should export app logs filtered by date range', (done) => {
const startDate = new Date();
startDate.setDate(startDate.getDate() - 1); // 1 day ago
diff --git a/packages/rest-typings/src/apps/appLogsExportProps.ts b/packages/rest-typings/src/apps/appLogsExportProps.ts
index 9c1ecd6c9a33e..ff66255e4992b 100644
--- a/packages/rest-typings/src/apps/appLogsExportProps.ts
+++ b/packages/rest-typings/src/apps/appLogsExportProps.ts
@@ -10,6 +10,7 @@ const AppLogsExportPropsSchema = {
properties: {
logLevel: { type: 'string', enum: ['0', '1', '2'], nullable: true },
method: { type: 'string', nullable: true },
+ instanceId: { type: 'string', nullable: true },
startDate: { type: 'string', format: 'date-time', nullable: true },
endDate: { type: 'string', format: 'date-time', nullable: true },
type: { type: 'string', enum: ['json', 'csv'] },