diff --git a/source/commands/api/users/list.tsx b/source/commands/api/users/list.tsx index e4757e6b..5ae762d5 100644 --- a/source/commands/api/users/list.tsx +++ b/source/commands/api/users/list.tsx @@ -78,6 +78,15 @@ export const options = object({ alias: 'a', }), ), + includeResourceInstanceRoles: boolean() + .optional() + .default(false) + .describe( + option({ + description: 'Include resource instance roles in the response', + alias: 'i', + }), + ), }); type Props = { diff --git a/source/components/api/PermitUsersListComponent.tsx b/source/components/api/PermitUsersListComponent.tsx index f7ccac2a..4982dc92 100644 --- a/source/components/api/PermitUsersListComponent.tsx +++ b/source/components/api/PermitUsersListComponent.tsx @@ -8,7 +8,9 @@ import Spinner from 'ink-spinner'; import { usersApi, type UserData } from '../../utils/permitApi.js'; type Props = { - options: zInfer; + options: zInfer & { + includeResourceInstanceRoles?: boolean; + }; }; // Transforms API data into table-friendly format while preserving type safety @@ -79,6 +81,7 @@ export default function PermitUsersListComponent({ options }: Props) { perPage: options.perPage, role: options.role, tenant: options.tenant, + include_resource_instance_roles: options.includeResourceInstanceRoles, }); if (!response.success) { diff --git a/source/utils/permitApi.ts b/source/utils/permitApi.ts index 60c3700f..433f13a7 100644 --- a/source/utils/permitApi.ts +++ b/source/utils/permitApi.ts @@ -64,6 +64,7 @@ export interface ListUsersRequest extends PermitApiOptions { perPage?: number; role?: string; tenant?: string; + include_resource_instance_roles?: boolean; } export interface RoleAssignmentRequest extends PermitApiOptions { @@ -88,6 +89,11 @@ export const usersApi = { page: String(options.page || 1), per_page: String(options.perPage || 50), ...(options.role && { role: options.role }), + ...(options.include_resource_instance_roles !== undefined && { + include_resource_instance_roles: String( + options.include_resource_instance_roles, + ), + }), }, ); }, diff --git a/tests/api-users.test.tsx b/tests/api-users.test.tsx index c3d0f552..ecbec31b 100644 --- a/tests/api-users.test.tsx +++ b/tests/api-users.test.tsx @@ -162,6 +162,56 @@ describe('API Users List Command', () => { await delay(100); expect(lastFrame()?.toString()).toMatch(/Error/); }); + + it('should include resource instance roles when option is set', async () => { + (fetch as any).mockResolvedValue({ + ok: true, + json: async () => ({ + success: true, + data: [ + { + key: 'user1', + email: 'test@test.com', + first_name: 'Test', + last_name: 'User', + roles: [ + { + role: 'admin', + tenant: 'tenant1', + resource_instance: { + type: 'project', + key: 'proj1', + }, + }, + ], + }, + ], + total_count: 1, + page: 1, + }), + }); + + const options = { + apiKey: demoPermitKey, + page: 1, + perPage: 10, + all: false, + expandKey: false, + includeResourceInstanceRoles: true, + }; + + const { lastFrame } = render(); + expect(lastFrame()?.toString()).toMatch(/Loading Token/); + + await delay(100); + expect(lastFrame()).toMatch(/Showing 1 items/); + + // Verify the API was called with the correct parameter + expect(fetch).toHaveBeenCalledWith( + expect.stringContaining('include_resource_instance_roles=true'), + expect.any(Object), + ); + }); }); describe('API Users Commands', () => {