Files
probo/pkg/server/api/connect/v1/graphql/profile.graphql
Émile Ré eecf8a1d97 Make profile state filters multi-value
Address PR review feedback on the profile-state split: SAML sign-in now
activates a pending profile, deactivation counts owners against the
profile's own organization to close a last-owner bypass, the migration
leaves historical activated_at/deactivated_at NULL rather than
fabricating timestamps, and pending members are no longer rendered with
the deactivated (faded) styling.

Drop the single-value state filter in favor of the multi-value states
across the profile and signatory surfaces. Remove ProfileFilter.state
(only states[] remains) and convert the signatures profileState filter
to profileStates. Turn the console people filter, the CLI
"user list --state" flag, and the n8n listUsers and getAllSignatures
state inputs into multi-select controls, where an empty selection means
all states.

Signed-off-by: Émile Ré <emile@probo.com>
2026-07-30 09:19:42 +02:00

164 lines
4.1 KiB
GraphQL

type Profile implements Node {
id: ID!
fullName: String!
emailAddress: EmailAddr!
source: String!
state: ProfileState!
additionalEmailAddresses: [EmailAddr!]!
kind: String
position: String
contractStartDate: Datetime
contractEndDate: Datetime
createdAt: Datetime!
updatedAt: Datetime!
identity: Identity @goField(forceResolver: true)
organization: Organization @goField(forceResolver: true)
membership: Membership @goField(forceResolver: true)
pendingInvitations(
first: Int
after: CursorKey
last: Int
before: CursorKey
orderBy: InvitationOrder
): InvitationConnection @goField(forceResolver: true)
permission(action: String!): Boolean!
@goField(forceResolver: true)
@authentication(required: PRESENT)
}
enum ProfileState
@goModel(model: "go.probo.inc/probo/pkg/coredata.ProfileState") {
PENDING @goEnum(value: "go.probo.inc/probo/pkg/coredata.ProfileStatePending")
ACTIVE @goEnum(value: "go.probo.inc/probo/pkg/coredata.ProfileStateActive")
DEACTIVATED
@goEnum(value: "go.probo.inc/probo/pkg/coredata.ProfileStateDeactivated")
}
enum ProfileSource
@goModel(model: "go.probo.inc/probo/pkg/coredata.ProfileSource") {
MANUAL
@goEnum(value: "go.probo.inc/probo/pkg/coredata.ProfileSourceManual")
SAML @goEnum(value: "go.probo.inc/probo/pkg/coredata.ProfileSourceSAML")
SCIM @goEnum(value: "go.probo.inc/probo/pkg/coredata.ProfileSourceSCIM")
}
enum ProfileOrderField
@goModel(model: "go.probo.inc/probo/pkg/coredata.MembershipProfileOrderField") {
FULL_NAME
@goEnum(
value: "go.probo.inc/probo/pkg/coredata.MembershipProfileOrderFieldFullName"
)
CREATED_AT
@goEnum(
value: "go.probo.inc/probo/pkg/coredata.MembershipProfileOrderFieldCreatedAt"
)
EMAIL_ADDRESS
@goEnum(
value: "go.probo.inc/probo/pkg/coredata.MembershipProfileOrderFieldEmailAddress"
)
KIND @goEnum(value: "go.probo.inc/probo/pkg/coredata.MembershipProfileOrderFieldKind")
ORGANIZATION_NAME
@goEnum(
value: "go.probo.inc/probo/pkg/coredata.MembershipProfileOrderFieldOrganizationName"
)
STATE
@goEnum(
value: "go.probo.inc/probo/pkg/coredata.MembershipProfileOrderFieldState"
)
}
input ProfileFilter {
contractEnded: Boolean
states: [ProfileState!]
query: String
role: MembershipRole
kind: String
}
input ProfileOrder
@goModel(
model: "go.probo.inc/probo/pkg/server/api/connect/v1/types.ProfileOrderBy"
) {
direction: OrderDirection!
field: ProfileOrderField!
}
type ProfileConnection
@goModel(
model: "go.probo.inc/probo/pkg/server/api/connect/v1/types.ProfileConnection"
) {
totalCount: Int @goField(forceResolver: true)
edges: [ProfileEdge!]!
pageInfo: PageInfo!
}
type ProfileEdge {
cursor: CursorKey!
node: Profile!
}
extend type Mutation {
createUser(input: CreateUserInput!): CreateUserPayload
@authentication(required: PRESENT)
deactivateUser(input: DeactivateUserInput!): DeactivateUserPayload
@authentication(required: PRESENT)
updateUser(input: UpdateUserInput!): UpdateUserPayload!
removeUser(input: RemoveUserInput!): RemoveUserPayload
@authentication(required: PRESENT)
}
input CreateUserInput {
organizationId: ID!
fullName: String!
emailAddress: EmailAddr!
role: MembershipRole!
additionalEmailAddresses: [EmailAddr!]
kind: String
position: String
contractStartDate: Datetime @goField(omittable: true)
contractEndDate: Datetime @goField(omittable: true)
}
input ActivateUserInput {
organizationId: ID!
profileId: ID!
}
input DeactivateUserInput {
organizationId: ID!
profileId: ID!
}
input UpdateUserInput {
id: ID!
fullName: String!
additionalEmailAddresses: [EmailAddr!]
kind: String
position: String
contractStartDate: Datetime @goField(omittable: true)
contractEndDate: Datetime @goField(omittable: true)
}
input RemoveUserInput {
organizationId: ID!
profileId: ID!
}
type CreateUserPayload {
profileEdge: ProfileEdge!
}
type DeactivateUserPayload {
success: Boolean!
}
type UpdateUserPayload {
profile: Profile!
}
type RemoveUserPayload {
deletedProfileId: ID!
}