Files
probo/pkg/server/api/console/v1/graphql/organization.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

387 lines
10 KiB
GraphQL

type OrganizationContext {
organizationId: ID!
product: String
architecture: String
team: String
processes: String
customers: String
}
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 MembershipRole
@goModel(model: "go.probo.inc/probo/pkg/coredata.MembershipRole") {
OWNER @goEnum(value: "go.probo.inc/probo/pkg/coredata.MembershipRoleOwner")
ADMIN @goEnum(value: "go.probo.inc/probo/pkg/coredata.MembershipRoleAdmin")
EMPLOYEE
@goEnum(value: "go.probo.inc/probo/pkg/coredata.MembershipRoleEmployee")
VIEWER @goEnum(value: "go.probo.inc/probo/pkg/coredata.MembershipRoleViewer")
AUDITOR
@goEnum(value: "go.probo.inc/probo/pkg/coredata.MembershipRoleAuditor")
}
type Profile implements Node {
id: ID!
fullName: String!
emailAddress: EmailAddr!
state: ProfileState!
additionalEmailAddresses: [EmailAddr!]!
kind: String
position: String
contractStartDate: Datetime
contractEndDate: Datetime
createdAt: Datetime!
updatedAt: Datetime!
permission(action: String!): Boolean! @goField(forceResolver: true)
}
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")
}
input ProfileOrder
@goModel(
model: "go.probo.inc/probo/pkg/server/api/console/v1/types.ProfileOrderBy"
) {
direction: OrderDirection!
field: ProfileOrderField!
}
input ProfileFilter {
contractEnded: Boolean
states: [ProfileState!]
query: String
role: MembershipRole
kind: String
}
type ProfileConnection
@goModel(
model: "go.probo.inc/probo/pkg/server/api/console/v1/types.ProfileConnection"
) {
totalCount: Int! @goField(forceResolver: true)
edges: [ProfileEdge!]!
pageInfo: PageInfo!
}
type ProfileEdge {
cursor: CursorKey!
node: Profile!
}
input UpdateOrganizationContextInput {
organizationId: ID!
product: String @goField(omittable: true)
architecture: String @goField(omittable: true)
team: String @goField(omittable: true)
processes: String @goField(omittable: true)
customers: String @goField(omittable: true)
}
type UpdateOrganizationContextPayload {
context: OrganizationContext!
}
type Organization implements Node {
id: ID!
name: String!
logo: File @goField(forceResolver: true)
horizontalLogo: File @goField(forceResolver: true)
context: OrganizationContext @goField(forceResolver: true)
profiles(
first: Int
after: CursorKey
last: Int
before: CursorKey
orderBy: ProfileOrder
filter: ProfileFilter
): ProfileConnection! @goField(forceResolver: true)
measureCategories: [String!]! @goField(forceResolver: true)
accessReviewSources(
first: Int
after: CursorKey
last: Int
before: CursorKey
orderBy: AccessReviewSourceOrder
): AccessReviewSourceConnection! @goField(forceResolver: true)
accessReviewCampaigns(
first: Int
after: CursorKey
last: Int
before: CursorKey
orderBy: AccessReviewCampaignOrder
): AccessReviewCampaignConnection! @goField(forceResolver: true)
assetListDocument: Document @goField(forceResolver: true)
assets(
first: Int
after: CursorKey
last: Int
before: CursorKey
orderBy: AssetOrder
): AssetConnection! @goField(forceResolver: true)
dataListDocument: Document @goField(forceResolver: true)
data(
first: Int
after: CursorKey
last: Int
before: CursorKey
orderBy: DatumOrder
): DatumConnection! @goField(forceResolver: true)
audits(
first: Int
after: CursorKey
last: Int
before: CursorKey
orderBy: AuditOrder
): AuditConnection! @goField(forceResolver: true)
findingsDocument: Document @goField(forceResolver: true)
findings(
first: Int
after: CursorKey
last: Int
before: CursorKey
orderBy: FindingOrder
filter: FindingFilter
): FindingConnection @goField(forceResolver: true)
auditLogEntries(
first: Int
after: CursorKey
last: Int
before: CursorKey
orderBy: AuditLogEntryOrder
filter: AuditLogEntryFilter
): AuditLogEntryConnection! @goField(forceResolver: true)
slackConnections(
first: Int
after: CursorKey
last: Int
before: CursorKey
): SlackConnectionConnection! @goField(forceResolver: true)
slackOAuth2Scopes: [String!]! @goField(forceResolver: true)
connectors(filter: ConnectorFilter): [Connector!]! @goField(forceResolver: true)
controls(
first: Int
after: CursorKey
last: Int
before: CursorKey
orderBy: ControlOrder
filter: ControlFilter
): ControlConnection! @goField(forceResolver: true)
statementsOfApplicability(
first: Int
after: CursorKey
last: Int
before: CursorKey
orderBy: StatementOfApplicabilityOrder
): StatementOfApplicabilityConnection! @goField(forceResolver: true)
dataProtectionImpactAssessments(
first: Int
after: CursorKey
last: Int
before: CursorKey
orderBy: DataProtectionImpactAssessmentOrder
): DataProtectionImpactAssessmentConnection! @goField(forceResolver: true)
dataProtectionImpactAssessmentsDocument: Document
@goField(forceResolver: true)
transferImpactAssessments(
first: Int
after: CursorKey
last: Int
before: CursorKey
orderBy: TransferImpactAssessmentOrder
): TransferImpactAssessmentConnection! @goField(forceResolver: true)
transferImpactAssessmentsDocument: Document @goField(forceResolver: true)
documents(
first: Int
after: CursorKey
last: Int
before: CursorKey
orderBy: DocumentOrder
filter: DocumentFilter
): DocumentConnection! @goField(forceResolver: true)
frameworks(
first: Int
after: CursorKey
last: Int
before: CursorKey
orderBy: FrameworkOrder
): FrameworkConnection! @goField(forceResolver: true)
measures(
first: Int
after: CursorKey
last: Int
before: CursorKey
orderBy: MeasureOrder
filter: MeasureFilter
): MeasureConnection! @goField(forceResolver: true)
obligationsDocument: Document @goField(forceResolver: true)
obligations(
first: Int
after: CursorKey
last: Int
before: CursorKey
orderBy: ObligationOrder
): ObligationConnection! @goField(forceResolver: true)
processingActivities(
first: Int
after: CursorKey
last: Int
before: CursorKey
orderBy: ProcessingActivityOrder
): ProcessingActivityConnection! @goField(forceResolver: true)
processingActivitiesDocument: Document @goField(forceResolver: true)
rightsRequests(
first: Int
after: CursorKey
last: Int
before: CursorKey
orderBy: RightsRequestOrder
): RightsRequestConnection! @goField(forceResolver: true)
risks(
first: Int
after: CursorKey
last: Int
before: CursorKey
orderBy: RiskOrder
filter: RiskFilter
): RiskConnection! @goField(forceResolver: true)
risksDocument: Document @goField(forceResolver: true)
riskAssessments(
first: Int
after: CursorKey
last: Int
before: CursorKey
orderBy: RiskAssessmentOrder
): RiskAssessmentConnection! @goField(forceResolver: true)
riskAssessmentScenarios(
first: Int
after: CursorKey
last: Int
before: CursorKey
orderBy: RiskAssessmentScenarioOrder
): RiskAssessmentScenarioConnection @goField(forceResolver: true)
tasks(
first: Int
after: CursorKey
last: Int
before: CursorKey
orderBy: TaskOrder
): TaskConnection! @goField(forceResolver: true)
agentRuns(
first: Int
after: CursorKey
last: Int
before: CursorKey
orderBy: AgentRunOrder
): AgentRunConnection! @goField(forceResolver: true)
compliancePortal: CompliancePortal @goField(forceResolver: true)
compliancePortalFiles(
first: Int
after: CursorKey
last: Int
before: CursorKey
orderBy: CompliancePortalFileOrder
): CompliancePortalFileConnection! @goField(forceResolver: true)
cookieBanners(
first: Int
after: CursorKey
last: Int
before: CursorKey
orderBy: CookieBannerOrder
): CookieBannerConnection @goField(forceResolver: true)
thirdParties(
first: Int
after: CursorKey
last: Int
before: CursorKey
orderBy: ThirdPartyOrder
filter: ThirdPartyFilter
): ThirdPartyConnection! @goField(forceResolver: true)
thirdPartiesDocument: Document @goField(forceResolver: true)
devices(
first: Int
after: CursorKey
last: Int
before: CursorKey
orderBy: DeviceOrder
): DeviceConnection! @goField(forceResolver: true)
webhookSubscriptions(
first: Int
after: CursorKey
last: Int
before: CursorKey
orderBy: WebhookSubscriptionOrder
): WebhookSubscriptionConnection! @goField(forceResolver: true)
createdAt: Datetime!
updatedAt: Datetime!
permission(action: String!): Boolean! @goField(forceResolver: true)
}
extend type Mutation {
updateOrganizationContext(
input: UpdateOrganizationContextInput!
): UpdateOrganizationContextPayload!
}