Add search and status/role/type filters to People

Makes it practical to find people in larger orgs across GraphQL, MCP, CLI, and n8n, with page size raised to 100.

Signed-off-by: Sacha Al Himdani <sacha@probo.com>
This commit is contained in:
Sacha Al Himdani
2026-07-27 14:46:15 +02:00
parent edb67743ae
commit d61ec8dd65
19 changed files with 624 additions and 123 deletions

View File

@@ -120,7 +120,13 @@ export {
export { getTrackerTypeBadge, getTrackerSourceBadge } from "./tracker";
export { detectSocialName } from "./socialUrl";
export { formatError, type GraphQLError } from "./error";
export { Role, roles, getAssignableRoles } from "./roles";
export {
Role,
roles,
getAssignableRoles,
getMembershipRole,
getMembershipRoles,
} from "./roles";
export {
getCompliancePortalDocumentAccessStatusBadgeVariant,
getCompliancePortalDocumentAccessStatusLabel,

View File

@@ -18,6 +18,8 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
type Translator = (s: string) => string;
export const Role = {
OWNER: "OWNER",
ADMIN: "ADMIN",
@@ -46,3 +48,45 @@ export function getAssignableRoles(currentRole: Role): Role[] {
return [];
}
export function getMembershipRoles(t: Translator) {
return [
{
value: Role.OWNER,
label: t("helpers.membershipRole.owner"),
},
{
value: Role.ADMIN,
label: t("helpers.membershipRole.admin"),
},
{
value: Role.VIEWER,
label: t("helpers.membershipRole.viewer"),
},
{
value: Role.AUDITOR,
label: t("helpers.membershipRole.auditor"),
},
{
value: Role.EMPLOYEE,
label: t("helpers.membershipRole.employee"),
},
] as const;
}
export function getMembershipRole(t: Translator, role?: string): string {
switch (role) {
case Role.OWNER:
return t("helpers.membershipRole.owner");
case Role.ADMIN:
return t("helpers.membershipRole.admin");
case Role.VIEWER:
return t("helpers.membershipRole.viewer");
case Role.AUDITOR:
return t("helpers.membershipRole.auditor");
case Role.EMPLOYEE:
return t("helpers.membershipRole.employee");
default:
return t("helpers.common.unknown");
}
}

View File

@@ -71,6 +71,77 @@ export const description: INodeProperties[] = [
default: 50,
description: 'Max number of results to return',
},
{
displayName: 'Search',
name: 'query',
type: 'string',
displayOptions: {
show: {
resource: ['user'],
operation: ['listUsers'],
},
},
default: '',
description: 'Search users by full name or email address',
},
{
displayName: 'State',
name: 'state',
type: 'options',
displayOptions: {
show: {
resource: ['user'],
operation: ['listUsers'],
},
},
options: [
{ name: 'Active', value: 'ACTIVE' },
{ name: 'All', value: '' },
{ name: 'Inactive', value: 'INACTIVE' },
],
default: '',
description: 'Filter by profile state',
},
{
displayName: 'Role',
name: 'role',
type: 'options',
displayOptions: {
show: {
resource: ['user'],
operation: ['listUsers'],
},
},
options: [
{ name: 'Admin', value: 'ADMIN' },
{ name: 'All', value: '' },
{ name: 'Auditor', value: 'AUDITOR' },
{ name: 'Employee', value: 'EMPLOYEE' },
{ name: 'Owner', value: 'OWNER' },
{ name: 'Viewer', value: 'VIEWER' },
],
default: '',
description: 'Filter by membership role',
},
{
displayName: 'Type',
name: 'kind',
type: 'options',
displayOptions: {
show: {
resource: ['user'],
operation: ['listUsers'],
},
},
options: [
{ name: 'All', value: '' },
{ name: 'Contractor', value: 'CONTRACTOR' },
{ name: 'Employee', value: 'EMPLOYEE' },
{ name: 'Service Account', value: 'SERVICE_ACCOUNT' },
],
default: '',
description: 'Filter by profile kind',
},
];
export async function execute(
@@ -80,12 +151,16 @@ export async function execute(
const organizationId = this.getNodeParameter('organizationId', itemIndex) as string;
const returnAll = this.getNodeParameter('returnAll', itemIndex) as boolean;
const limit = this.getNodeParameter('limit', itemIndex, 50) as number;
const query = this.getNodeParameter('query', itemIndex, '') as string;
const state = this.getNodeParameter('state', itemIndex, '') as string;
const role = this.getNodeParameter('role', itemIndex, '') as string;
const kind = this.getNodeParameter('kind', itemIndex, '') as string;
const query = `
query ListUsers($organizationId: ID!, $first: Int, $after: CursorKey, $orderBy: ProfileOrder) {
const gqlQuery = `
query ListUsers($organizationId: ID!, $first: Int, $after: CursorKey, $orderBy: ProfileOrder, $filter: ProfileFilter) {
node(id: $organizationId) {
... on Organization {
profiles(first: $first, after: $after, orderBy: $orderBy) {
profiles(first: $first, after: $after, orderBy: $orderBy, filter: $filter) {
edges {
node {
id
@@ -114,10 +189,27 @@ export async function execute(
}
`;
const filter: IDataObject = {};
if (query) {
filter.query = query;
}
if (state) {
filter.state = state;
}
if (role) {
filter.role = role;
}
if (kind) {
filter.kind = kind;
}
const users = await proboConnectApiRequestAllItems.call(
this,
query,
{ organizationId },
gqlQuery,
{
organizationId,
...(Object.keys(filter).length > 0 ? { filter } : {}),
},
(response: IDataObject) => {
const data = response?.data as IDataObject | undefined;
const node = data?.node as IDataObject | undefined;