diff --git a/packages/insomnia/src/common/__tests__/insomnia-v5.test.ts b/packages/insomnia/src/common/__tests__/insomnia-v5.test.ts index 0e72939487..6ab506a980 100644 --- a/packages/insomnia/src/common/__tests__/insomnia-v5.test.ts +++ b/packages/insomnia/src/common/__tests__/insomnia-v5.test.ts @@ -369,6 +369,62 @@ spec: expect(parsed.collection[0].name).toBe('Request 1'); }); + it('omits folders that contain no selected requests', async () => { + const workspace = await services.workspace.create({ + _id: 'wrk_folder_filter', + name: 'Folder Filter Workspace', + parentId: 'proj_test', + scope: 'collection', + }); + await services.environment.create({ + _id: 'env_folder_filter', + name: 'Base Env', + parentId: workspace._id, + data: {}, + }); + const keptOuter = await services.requestGroup.create({ + _id: 'fld_kept_outer', + name: 'Kept', + parentId: workspace._id, + }); + const keptInner = await services.requestGroup.create({ + _id: 'fld_kept_inner', + name: 'Inner', + parentId: keptOuter._id, + }); + const skipped = await services.requestGroup.create({ + _id: 'fld_skipped', + name: 'Skipped', + parentId: workspace._id, + }); + const selected = await services.request.create({ + _id: 'req_selected', + name: 'Selected', + parentId: keptInner._id, + url: 'https://api.example.com/selected', + method: 'GET', + }); + await services.request.create({ + _id: 'req_unselected', + name: 'Unselected', + parentId: skipped._id, + url: 'https://api.example.com/unselected', + method: 'GET', + }); + + const result = await getInsomniaV5DataExport({ + workspaceId: workspace._id, + includePrivateEnvironments: false, + requestIds: [selected._id], + }); + + const parsed = YAML.parse(result); + expect(parsed.collection).toHaveLength(1); + expect(parsed.collection[0].name).toBe('Kept'); + expect(parsed.collection[0].children[0].name).toBe('Inner'); + expect(parsed.collection[0].children[0].children[0].name).toBe('Selected'); + }); + it('handles design workspace correctly', async () => { const workspace = await services.workspace.create({ _id: 'wrk_design_test', diff --git a/packages/insomnia/src/common/insomnia-v5.ts b/packages/insomnia/src/common/insomnia-v5.ts index fe9acf5b49..fdd56993da 100644 --- a/packages/insomnia/src/common/insomnia-v5.ts +++ b/packages/insomnia/src/common/insomnia-v5.ts @@ -1085,6 +1085,19 @@ export async function getInsomniaV5DataExport({ exportableResources.filter(models.webSocketPayload.isWebSocketPayload).map(payload => [payload.parentId, payload]), ); + // When exporting a subset of requests, only keep the folders that contain at least one of them + const requestGroupIdsToKeep = new Set(); + if (requestIds && requestIds.length > 0) { + const parentIdById = new Map(exportableResources.map(resource => [resource._id, resource.parentId])); + for (const requestId of requestIds) { + let parentId = parentIdById.get(requestId); + while (parentId && !requestGroupIdsToKeep.has(parentId)) { + requestGroupIdsToKeep.add(parentId); + parentId = parentIdById.get(parentId); + } + } + } + /** * Recursively builds a collection structure from flat resource list * This function converts the flat list of resources into a hierarchical structure @@ -1103,10 +1116,13 @@ export async function getInsomniaV5DataExport({ // Filter resources based on requestIds filter and parent relationship resources .filter(resource => { - // Include all request groups, or filter by requestIds if specified - if (!requestIds || requestIds.length === 0 || models.requestGroup.isRequestGroup(resource)) { + // Include everything, or filter by requestIds if specified (folders are kept only if they contain a selected request) + if (!requestIds || requestIds.length === 0) { return true; } + if (models.requestGroup.isRequestGroup(resource)) { + return requestGroupIdsToKeep.has(resource._id); + } return requestIds.includes(resource._id); })