Add configurable compliance portal commitment cards

The compliance portal home page rendered security-commitment cards from
a hardcoded placeholder POJO. Back them with real, per-organization data
that admins configure in the console and the portal loads over the trust
center GraphQL API.

Model two entities under the trust center: a commitment group (title,
description, rank) and a commitment card (icon, eyebrow, title,
description, rank). The card icon is a curated enum mapped to a Phosphor
icon in the portal. New entities adopt the compliance_portal_ prefix as
the start of the broader rename away from trust_center_ naming.

Expose the groups and cards read-only on the public trust API and with
full CRUD on the console API, add a Commitments tab to the compliance
page, and replace the placeholder section with a Relay-driven one.

Signed-off-by: Émile Ré <emile@probo.com>
This commit is contained in:
Émile Ré
2026-07-16 13:36:44 +02:00
parent 936162d5c7
commit 0b146a4054
39 changed files with 4079 additions and 175 deletions

View File

@@ -106,6 +106,88 @@ enum TrustCenterReferenceOrderField
)
}
enum CompliancePortalCommitmentGroupOrderField
@goModel(
model: "go.probo.inc/probo/pkg/coredata.CompliancePortalCommitmentGroupOrderField"
) {
RANK
@goEnum(
value: "go.probo.inc/probo/pkg/coredata.CompliancePortalCommitmentGroupOrderFieldRank"
)
CREATED_AT
@goEnum(
value: "go.probo.inc/probo/pkg/coredata.CompliancePortalCommitmentGroupOrderFieldCreatedAt"
)
UPDATED_AT
@goEnum(
value: "go.probo.inc/probo/pkg/coredata.CompliancePortalCommitmentGroupOrderFieldUpdatedAt"
)
}
enum CompliancePortalCommitmentOrderField
@goModel(
model: "go.probo.inc/probo/pkg/coredata.CompliancePortalCommitmentOrderField"
) {
RANK
@goEnum(
value: "go.probo.inc/probo/pkg/coredata.CompliancePortalCommitmentOrderFieldRank"
)
CREATED_AT
@goEnum(
value: "go.probo.inc/probo/pkg/coredata.CompliancePortalCommitmentOrderFieldCreatedAt"
)
UPDATED_AT
@goEnum(
value: "go.probo.inc/probo/pkg/coredata.CompliancePortalCommitmentOrderFieldUpdatedAt"
)
}
enum CompliancePortalCommitmentIcon
@goModel(
model: "go.probo.inc/probo/pkg/coredata.CompliancePortalCommitmentIcon"
) {
LOCK_KEY
@goEnum(value: "go.probo.inc/probo/pkg/coredata.CompliancePortalCommitmentIconLockKey")
EYE_SLASH
@goEnum(value: "go.probo.inc/probo/pkg/coredata.CompliancePortalCommitmentIconEyeSlash")
FINGERPRINT
@goEnum(value: "go.probo.inc/probo/pkg/coredata.CompliancePortalCommitmentIconFingerprint")
SHIELD_WARNING
@goEnum(value: "go.probo.inc/probo/pkg/coredata.CompliancePortalCommitmentIconShieldWarning")
SHIELD_CHECK
@goEnum(value: "go.probo.inc/probo/pkg/coredata.CompliancePortalCommitmentIconShieldCheck")
SIREN
@goEnum(value: "go.probo.inc/probo/pkg/coredata.CompliancePortalCommitmentIconSiren")
KEY
@goEnum(value: "go.probo.inc/probo/pkg/coredata.CompliancePortalCommitmentIconKey")
LOCK
@goEnum(value: "go.probo.inc/probo/pkg/coredata.CompliancePortalCommitmentIconLock")
CLOUD
@goEnum(value: "go.probo.inc/probo/pkg/coredata.CompliancePortalCommitmentIconCloud")
DATABASE
@goEnum(value: "go.probo.inc/probo/pkg/coredata.CompliancePortalCommitmentIconDatabase")
GLOBE
@goEnum(value: "go.probo.inc/probo/pkg/coredata.CompliancePortalCommitmentIconGlobe")
EYE
@goEnum(value: "go.probo.inc/probo/pkg/coredata.CompliancePortalCommitmentIconEye")
USERS
@goEnum(value: "go.probo.inc/probo/pkg/coredata.CompliancePortalCommitmentIconUsers")
CERTIFICATE
@goEnum(value: "go.probo.inc/probo/pkg/coredata.CompliancePortalCommitmentIconCertificate")
GAVEL
@goEnum(value: "go.probo.inc/probo/pkg/coredata.CompliancePortalCommitmentIconGavel")
HEARTBEAT
@goEnum(value: "go.probo.inc/probo/pkg/coredata.CompliancePortalCommitmentIconHeartbeat")
BELL
@goEnum(value: "go.probo.inc/probo/pkg/coredata.CompliancePortalCommitmentIconBell")
BUG
@goEnum(value: "go.probo.inc/probo/pkg/coredata.CompliancePortalCommitmentIconBug")
CODE
@goEnum(value: "go.probo.inc/probo/pkg/coredata.CompliancePortalCommitmentIconCode")
SERVER
@goEnum(value: "go.probo.inc/probo/pkg/coredata.CompliancePortalCommitmentIconServer")
}
enum ComplianceExternalURLOrderField
@goModel(
model: "go.probo.inc/probo/pkg/coredata.ComplianceExternalURLOrderField"
@@ -218,6 +300,22 @@ input TrustCenterReferenceOrder
field: TrustCenterReferenceOrderField!
}
input CompliancePortalCommitmentGroupOrder
@goModel(
model: "go.probo.inc/probo/pkg/server/api/console/v1/types.CompliancePortalCommitmentGroupOrderBy"
) {
direction: OrderDirection!
field: CompliancePortalCommitmentGroupOrderField!
}
input CompliancePortalCommitmentOrder
@goModel(
model: "go.probo.inc/probo/pkg/server/api/console/v1/types.CompliancePortalCommitmentOrderBy"
) {
direction: OrderDirection!
field: CompliancePortalCommitmentOrderField!
}
input TrustCenterFileOrder
@goModel(
model: "go.probo.inc/probo/pkg/server/api/console/v1/types.TrustCenterFileOrderBy"
@@ -272,6 +370,14 @@ type TrustCenter implements Node
orderBy: TrustCenterReferenceOrder
): TrustCenterReferenceConnection! @goField(forceResolver: true)
commitmentGroups(
first: Int
after: CursorKey
last: Int
before: CursorKey
orderBy: CompliancePortalCommitmentGroupOrder
): CompliancePortalCommitmentGroupConnection! @goField(forceResolver: true)
complianceFrameworks(
first: Int
after: CursorKey
@@ -389,6 +495,66 @@ type TrustCenterReferenceEdge {
node: TrustCenterReference!
}
type CompliancePortalCommitmentGroup implements Node {
id: ID!
title: String!
description: String!
rank: Int!
createdAt: Datetime!
updatedAt: Datetime!
commitments(
first: Int
after: CursorKey
last: Int
before: CursorKey
orderBy: CompliancePortalCommitmentOrder
): CompliancePortalCommitmentConnection! @goField(forceResolver: true)
permission(action: String!): Boolean! @goField(forceResolver: true)
}
type CompliancePortalCommitmentGroupConnection
@goModel(
model: "go.probo.inc/probo/pkg/server/api/console/v1/types.CompliancePortalCommitmentGroupConnection"
) {
totalCount: Int! @goField(forceResolver: true)
edges: [CompliancePortalCommitmentGroupEdge!]!
pageInfo: PageInfo!
}
type CompliancePortalCommitmentGroupEdge {
cursor: CursorKey!
node: CompliancePortalCommitmentGroup!
}
type CompliancePortalCommitment implements Node {
id: ID!
icon: CompliancePortalCommitmentIcon!
eyebrow: String!
title: String!
description: String!
rank: Int!
createdAt: Datetime!
updatedAt: Datetime!
permission(action: String!): Boolean! @goField(forceResolver: true)
}
type CompliancePortalCommitmentConnection
@goModel(
model: "go.probo.inc/probo/pkg/server/api/console/v1/types.CompliancePortalCommitmentConnection"
) {
totalCount: Int! @goField(forceResolver: true)
edges: [CompliancePortalCommitmentEdge!]!
pageInfo: PageInfo!
}
type CompliancePortalCommitmentEdge {
cursor: CursorKey!
node: CompliancePortalCommitment!
}
type ComplianceFramework implements Node
@goModel(
model: "go.probo.inc/probo/pkg/server/api/console/v1/types.ComplianceFramework"
@@ -514,6 +680,24 @@ extend type Mutation {
deleteTrustCenterReference(
input: DeleteTrustCenterReferenceInput!
): DeleteTrustCenterReferencePayload!
createCompliancePortalCommitmentGroup(
input: CreateCompliancePortalCommitmentGroupInput!
): CreateCompliancePortalCommitmentGroupPayload!
updateCompliancePortalCommitmentGroup(
input: UpdateCompliancePortalCommitmentGroupInput!
): UpdateCompliancePortalCommitmentGroupPayload!
deleteCompliancePortalCommitmentGroup(
input: DeleteCompliancePortalCommitmentGroupInput!
): DeleteCompliancePortalCommitmentGroupPayload!
createCompliancePortalCommitment(
input: CreateCompliancePortalCommitmentInput!
): CreateCompliancePortalCommitmentPayload!
updateCompliancePortalCommitment(
input: UpdateCompliancePortalCommitmentInput!
): UpdateCompliancePortalCommitmentPayload!
deleteCompliancePortalCommitment(
input: DeleteCompliancePortalCommitmentInput!
): DeleteCompliancePortalCommitmentPayload!
createComplianceFramework(
input: CreateComplianceFrameworkInput!
): CreateComplianceFrameworkPayload!
@@ -613,6 +797,44 @@ input DeleteTrustCenterReferenceInput {
id: ID!
}
input CreateCompliancePortalCommitmentGroupInput {
trustCenterId: ID!
title: String!
description: String!
}
input UpdateCompliancePortalCommitmentGroupInput {
id: ID!
title: String
description: String
rank: Int
}
input DeleteCompliancePortalCommitmentGroupInput {
id: ID!
}
input CreateCompliancePortalCommitmentInput {
groupId: ID!
icon: CompliancePortalCommitmentIcon!
eyebrow: String!
title: String!
description: String!
}
input UpdateCompliancePortalCommitmentInput {
id: ID!
icon: CompliancePortalCommitmentIcon
eyebrow: String
title: String
description: String
rank: Int
}
input DeleteCompliancePortalCommitmentInput {
id: ID!
}
input CreateComplianceFrameworkInput {
trustCenterId: ID!
frameworkId: ID!
@@ -712,6 +934,30 @@ type DeleteTrustCenterReferencePayload {
deletedTrustCenterReferenceId: ID!
}
type CreateCompliancePortalCommitmentGroupPayload {
compliancePortalCommitmentGroupEdge: CompliancePortalCommitmentGroupEdge!
}
type UpdateCompliancePortalCommitmentGroupPayload {
compliancePortalCommitmentGroup: CompliancePortalCommitmentGroup!
}
type DeleteCompliancePortalCommitmentGroupPayload {
deletedCompliancePortalCommitmentGroupId: ID!
}
type CreateCompliancePortalCommitmentPayload {
compliancePortalCommitmentEdge: CompliancePortalCommitmentEdge!
}
type UpdateCompliancePortalCommitmentPayload {
compliancePortalCommitment: CompliancePortalCommitment!
}
type DeleteCompliancePortalCommitmentPayload {
deletedCompliancePortalCommitmentId: ID!
}
type CreateComplianceFrameworkPayload {
complianceFrameworkEdge: ComplianceFrameworkEdge!
}

View File

@@ -51,6 +51,78 @@ func (r *complianceFrameworkResolver) Framework(ctx context.Context, obj *types.
return types.NewFramework(framework), nil
}
// Permission is the resolver for the permission field.
func (r *compliancePortalCommitmentResolver) Permission(ctx context.Context, obj *types.CompliancePortalCommitment, action string) (bool, error) {
return r.Resolver.Permission(ctx, obj, action)
}
// TotalCount is the resolver for the totalCount field.
func (r *compliancePortalCommitmentConnectionResolver) TotalCount(ctx context.Context, obj *types.CompliancePortalCommitmentConnection) (int, error) {
scope, err := r.authorize(ctx, obj.ParentID, probo.ActionCompliancePortalCommitmentList)
if err != nil {
return 0, err
}
count, err := r.probo.CompliancePortalCommitments.CountForGroupID(ctx, scope, obj.ParentID)
if err != nil {
r.logger.ErrorCtx(ctx, "cannot count compliance portal commitments", log.Error(err))
return 0, gqlutils.Internal(ctx)
}
return count, nil
}
// Commitments is the resolver for the commitments field.
func (r *compliancePortalCommitmentGroupResolver) Commitments(ctx context.Context, obj *types.CompliancePortalCommitmentGroup, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.OrderBy[coredata.CompliancePortalCommitmentOrderField]) (*types.CompliancePortalCommitmentConnection, error) {
scope, err := r.authorize(ctx, obj.ID, probo.ActionCompliancePortalCommitmentList)
if err != nil {
return nil, err
}
pageOrderBy := page.OrderBy[coredata.CompliancePortalCommitmentOrderField]{
Field: coredata.CompliancePortalCommitmentOrderFieldRank,
Direction: page.OrderDirectionAsc,
}
if orderBy != nil {
pageOrderBy = page.OrderBy[coredata.CompliancePortalCommitmentOrderField]{
Field: orderBy.Field,
Direction: orderBy.Direction,
}
}
cursor := types.NewCursor(first, after, last, before, pageOrderBy)
result, err := r.probo.CompliancePortalCommitments.ListForGroupID(ctx, scope, obj.ID, cursor)
if err != nil {
r.logger.ErrorCtx(ctx, "cannot list compliance portal commitments", log.Error(err))
return nil, gqlutils.Internal(ctx)
}
return types.NewCompliancePortalCommitmentConnection(result, obj.ID), nil
}
// Permission is the resolver for the permission field.
func (r *compliancePortalCommitmentGroupResolver) Permission(ctx context.Context, obj *types.CompliancePortalCommitmentGroup, action string) (bool, error) {
return r.Resolver.Permission(ctx, obj, action)
}
// TotalCount is the resolver for the totalCount field.
func (r *compliancePortalCommitmentGroupConnectionResolver) TotalCount(ctx context.Context, obj *types.CompliancePortalCommitmentGroupConnection) (int, error) {
scope, err := r.authorize(ctx, obj.ParentID, probo.ActionCompliancePortalCommitmentGroupList)
if err != nil {
return 0, err
}
count, err := r.probo.CompliancePortalCommitmentGroups.CountForTrustCenterID(ctx, scope, obj.ParentID)
if err != nil {
r.logger.ErrorCtx(ctx, "cannot count compliance portal commitment groups", log.Error(err))
return 0, gqlutils.Internal(ctx)
}
return count, nil
}
// Permission is the resolver for the permission field.
func (r *customDomainResolver) Permission(ctx context.Context, obj *types.CustomDomain, action string) (bool, error) {
return r.Resolver.Permission(ctx, obj, action)
@@ -364,6 +436,166 @@ func (r *mutationResolver) DeleteTrustCenterReference(ctx context.Context, input
}, nil
}
// CreateCompliancePortalCommitmentGroup is the resolver for the createCompliancePortalCommitmentGroup field.
func (r *mutationResolver) CreateCompliancePortalCommitmentGroup(ctx context.Context, input types.CreateCompliancePortalCommitmentGroupInput) (*types.CreateCompliancePortalCommitmentGroupPayload, error) {
scope, err := r.authorize(ctx, input.TrustCenterID, probo.ActionCompliancePortalCommitmentGroupCreate)
if err != nil {
return nil, err
}
group, err := r.probo.CompliancePortalCommitmentGroups.Create(
ctx, scope,
&probo.CreateCompliancePortalCommitmentGroupRequest{
TrustCenterID: input.TrustCenterID,
Title: input.Title,
Description: input.Description,
},
)
if err != nil {
if validationErrors, ok := errors.AsType[validator.ValidationErrors](err); ok {
return nil, gqlutils.InvalidValidationErrors(ctx, validationErrors)
}
r.logger.ErrorCtx(ctx, "cannot create compliance portal commitment group", log.Error(err))
return nil, gqlutils.Internal(ctx)
}
return &types.CreateCompliancePortalCommitmentGroupPayload{
CompliancePortalCommitmentGroupEdge: types.NewCompliancePortalCommitmentGroupEdge(group, coredata.CompliancePortalCommitmentGroupOrderFieldRank),
}, nil
}
// UpdateCompliancePortalCommitmentGroup is the resolver for the updateCompliancePortalCommitmentGroup field.
func (r *mutationResolver) UpdateCompliancePortalCommitmentGroup(ctx context.Context, input types.UpdateCompliancePortalCommitmentGroupInput) (*types.UpdateCompliancePortalCommitmentGroupPayload, error) {
scope, err := r.authorize(ctx, input.ID, probo.ActionCompliancePortalCommitmentGroupUpdate)
if err != nil {
return nil, err
}
group, err := r.probo.CompliancePortalCommitmentGroups.Update(
ctx, scope,
&probo.UpdateCompliancePortalCommitmentGroupRequest{
ID: input.ID,
Title: input.Title,
Description: input.Description,
Rank: input.Rank,
},
)
if err != nil {
if validationErrors, ok := errors.AsType[validator.ValidationErrors](err); ok {
return nil, gqlutils.InvalidValidationErrors(ctx, validationErrors)
}
r.logger.ErrorCtx(ctx, "cannot update compliance portal commitment group", log.Error(err))
return nil, gqlutils.Internal(ctx)
}
return &types.UpdateCompliancePortalCommitmentGroupPayload{
CompliancePortalCommitmentGroup: types.NewCompliancePortalCommitmentGroup(group),
}, nil
}
// DeleteCompliancePortalCommitmentGroup is the resolver for the deleteCompliancePortalCommitmentGroup field.
func (r *mutationResolver) DeleteCompliancePortalCommitmentGroup(ctx context.Context, input types.DeleteCompliancePortalCommitmentGroupInput) (*types.DeleteCompliancePortalCommitmentGroupPayload, error) {
scope, err := r.authorize(ctx, input.ID, probo.ActionCompliancePortalCommitmentGroupDelete)
if err != nil {
return nil, err
}
if err := r.probo.CompliancePortalCommitmentGroups.Delete(ctx, scope, input.ID); err != nil {
r.logger.ErrorCtx(ctx, "cannot delete compliance portal commitment group", log.Error(err))
return nil, gqlutils.Internal(ctx)
}
return &types.DeleteCompliancePortalCommitmentGroupPayload{
DeletedCompliancePortalCommitmentGroupID: input.ID,
}, nil
}
// CreateCompliancePortalCommitment is the resolver for the createCompliancePortalCommitment field.
func (r *mutationResolver) CreateCompliancePortalCommitment(ctx context.Context, input types.CreateCompliancePortalCommitmentInput) (*types.CreateCompliancePortalCommitmentPayload, error) {
scope, err := r.authorize(ctx, input.GroupID, probo.ActionCompliancePortalCommitmentCreate)
if err != nil {
return nil, err
}
commitment, err := r.probo.CompliancePortalCommitments.Create(
ctx, scope,
&probo.CreateCompliancePortalCommitmentRequest{
GroupID: input.GroupID,
Icon: input.Icon,
Eyebrow: input.Eyebrow,
Title: input.Title,
Description: input.Description,
},
)
if err != nil {
if validationErrors, ok := errors.AsType[validator.ValidationErrors](err); ok {
return nil, gqlutils.InvalidValidationErrors(ctx, validationErrors)
}
r.logger.ErrorCtx(ctx, "cannot create compliance portal commitment", log.Error(err))
return nil, gqlutils.Internal(ctx)
}
return &types.CreateCompliancePortalCommitmentPayload{
CompliancePortalCommitmentEdge: types.NewCompliancePortalCommitmentEdge(commitment, coredata.CompliancePortalCommitmentOrderFieldRank),
}, nil
}
// UpdateCompliancePortalCommitment is the resolver for the updateCompliancePortalCommitment field.
func (r *mutationResolver) UpdateCompliancePortalCommitment(ctx context.Context, input types.UpdateCompliancePortalCommitmentInput) (*types.UpdateCompliancePortalCommitmentPayload, error) {
scope, err := r.authorize(ctx, input.ID, probo.ActionCompliancePortalCommitmentUpdate)
if err != nil {
return nil, err
}
commitment, err := r.probo.CompliancePortalCommitments.Update(
ctx, scope,
&probo.UpdateCompliancePortalCommitmentRequest{
ID: input.ID,
Icon: input.Icon,
Eyebrow: input.Eyebrow,
Title: input.Title,
Description: input.Description,
Rank: input.Rank,
},
)
if err != nil {
if validationErrors, ok := errors.AsType[validator.ValidationErrors](err); ok {
return nil, gqlutils.InvalidValidationErrors(ctx, validationErrors)
}
r.logger.ErrorCtx(ctx, "cannot update compliance portal commitment", log.Error(err))
return nil, gqlutils.Internal(ctx)
}
return &types.UpdateCompliancePortalCommitmentPayload{
CompliancePortalCommitment: types.NewCompliancePortalCommitment(commitment),
}, nil
}
// DeleteCompliancePortalCommitment is the resolver for the deleteCompliancePortalCommitment field.
func (r *mutationResolver) DeleteCompliancePortalCommitment(ctx context.Context, input types.DeleteCompliancePortalCommitmentInput) (*types.DeleteCompliancePortalCommitmentPayload, error) {
scope, err := r.authorize(ctx, input.ID, probo.ActionCompliancePortalCommitmentDelete)
if err != nil {
return nil, err
}
if err := r.probo.CompliancePortalCommitments.Delete(ctx, scope, input.ID); err != nil {
r.logger.ErrorCtx(ctx, "cannot delete compliance portal commitment", log.Error(err))
return nil, gqlutils.Internal(ctx)
}
return &types.DeleteCompliancePortalCommitmentPayload{
DeletedCompliancePortalCommitmentID: input.ID,
}, nil
}
// CreateComplianceFramework is the resolver for the createComplianceFramework field.
func (r *mutationResolver) CreateComplianceFramework(ctx context.Context, input types.CreateComplianceFrameworkInput) (*types.CreateComplianceFrameworkPayload, error) {
scope, err := r.authorize(ctx, input.TrustCenterID, probo.ActionComplianceFrameworkCreate)
@@ -817,6 +1049,36 @@ func (r *trustCenterResolver) References(ctx context.Context, obj *types.TrustCe
return types.NewTrustCenterReferenceConnection(result, obj.ID), nil
}
// CommitmentGroups is the resolver for the commitmentGroups field.
func (r *trustCenterResolver) CommitmentGroups(ctx context.Context, obj *types.TrustCenter, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.OrderBy[coredata.CompliancePortalCommitmentGroupOrderField]) (*types.CompliancePortalCommitmentGroupConnection, error) {
scope, err := r.authorize(ctx, obj.ID, probo.ActionCompliancePortalCommitmentGroupList)
if err != nil {
return nil, err
}
pageOrderBy := page.OrderBy[coredata.CompliancePortalCommitmentGroupOrderField]{
Field: coredata.CompliancePortalCommitmentGroupOrderFieldRank,
Direction: page.OrderDirectionAsc,
}
if orderBy != nil {
pageOrderBy = page.OrderBy[coredata.CompliancePortalCommitmentGroupOrderField]{
Field: orderBy.Field,
Direction: orderBy.Direction,
}
}
cursor := types.NewCursor(first, after, last, before, pageOrderBy)
result, err := r.probo.CompliancePortalCommitmentGroups.ListForTrustCenterID(ctx, scope, obj.ID, cursor)
if err != nil {
r.logger.ErrorCtx(ctx, "cannot list compliance portal commitment groups", log.Error(err))
return nil, gqlutils.Internal(ctx)
}
return types.NewCompliancePortalCommitmentGroupConnection(result, obj.ID), nil
}
// ComplianceFrameworks is the resolver for the complianceFrameworks field.
func (r *trustCenterResolver) ComplianceFrameworks(ctx context.Context, obj *types.TrustCenter, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.OrderBy[coredata.ComplianceFrameworkOrderField]) (*types.ComplianceFrameworkConnection, error) {
scope, err := r.authorize(ctx, obj.ID, probo.ActionComplianceFrameworkList)
@@ -1236,6 +1498,26 @@ func (r *Resolver) ComplianceFramework() schema.ComplianceFrameworkResolver {
return &complianceFrameworkResolver{r}
}
// CompliancePortalCommitment returns schema.CompliancePortalCommitmentResolver implementation.
func (r *Resolver) CompliancePortalCommitment() schema.CompliancePortalCommitmentResolver {
return &compliancePortalCommitmentResolver{r}
}
// CompliancePortalCommitmentConnection returns schema.CompliancePortalCommitmentConnectionResolver implementation.
func (r *Resolver) CompliancePortalCommitmentConnection() schema.CompliancePortalCommitmentConnectionResolver {
return &compliancePortalCommitmentConnectionResolver{r}
}
// CompliancePortalCommitmentGroup returns schema.CompliancePortalCommitmentGroupResolver implementation.
func (r *Resolver) CompliancePortalCommitmentGroup() schema.CompliancePortalCommitmentGroupResolver {
return &compliancePortalCommitmentGroupResolver{r}
}
// CompliancePortalCommitmentGroupConnection returns schema.CompliancePortalCommitmentGroupConnectionResolver implementation.
func (r *Resolver) CompliancePortalCommitmentGroupConnection() schema.CompliancePortalCommitmentGroupConnectionResolver {
return &compliancePortalCommitmentGroupConnectionResolver{r}
}
// CustomDomain returns schema.CustomDomainResolver implementation.
func (r *Resolver) CustomDomain() schema.CustomDomainResolver { return &customDomainResolver{r} }
@@ -1278,15 +1560,19 @@ func (r *Resolver) TrustCenterReferenceConnection() schema.TrustCenterReferenceC
}
type (
complianceExternalURLResolver struct{ *Resolver }
complianceFrameworkResolver struct{ *Resolver }
customDomainResolver struct{ *Resolver }
trustCenterResolver struct{ *Resolver }
trustCenterAccessResolver struct{ *Resolver }
trustCenterDocumentAccessResolver struct{ *Resolver }
trustCenterDocumentAccessConnectionResolver struct{ *Resolver }
trustCenterFileResolver struct{ *Resolver }
trustCenterFileConnectionResolver struct{ *Resolver }
trustCenterReferenceResolver struct{ *Resolver }
trustCenterReferenceConnectionResolver struct{ *Resolver }
complianceExternalURLResolver struct{ *Resolver }
complianceFrameworkResolver struct{ *Resolver }
compliancePortalCommitmentResolver struct{ *Resolver }
compliancePortalCommitmentConnectionResolver struct{ *Resolver }
compliancePortalCommitmentGroupResolver struct{ *Resolver }
compliancePortalCommitmentGroupConnectionResolver struct{ *Resolver }
customDomainResolver struct{ *Resolver }
trustCenterResolver struct{ *Resolver }
trustCenterAccessResolver struct{ *Resolver }
trustCenterDocumentAccessResolver struct{ *Resolver }
trustCenterDocumentAccessConnectionResolver struct{ *Resolver }
trustCenterFileResolver struct{ *Resolver }
trustCenterFileConnectionResolver struct{ *Resolver }
trustCenterReferenceResolver struct{ *Resolver }
trustCenterReferenceConnectionResolver struct{ *Resolver }
)

View File

@@ -0,0 +1,125 @@
// Copyright (c) 2026 Probo Inc <hello@probo.com>.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
package types
import (
"go.probo.inc/probo/pkg/coredata"
"go.probo.inc/probo/pkg/gid"
"go.probo.inc/probo/pkg/page"
)
type (
CompliancePortalCommitmentGroupOrderBy = OrderBy[coredata.CompliancePortalCommitmentGroupOrderField]
CompliancePortalCommitmentGroupConnection struct {
TotalCount int `json:"totalCount"`
Edges []*CompliancePortalCommitmentGroupEdge `json:"edges"`
PageInfo *PageInfo `json:"pageInfo"`
ParentID gid.GID `json:"-"`
}
CompliancePortalCommitmentOrderBy = OrderBy[coredata.CompliancePortalCommitmentOrderField]
CompliancePortalCommitmentConnection struct {
TotalCount int `json:"totalCount"`
Edges []*CompliancePortalCommitmentEdge `json:"edges"`
PageInfo *PageInfo `json:"pageInfo"`
ParentID gid.GID `json:"-"`
}
)
func NewCompliancePortalCommitmentGroup(g *coredata.CompliancePortalCommitmentGroup) *CompliancePortalCommitmentGroup {
return &CompliancePortalCommitmentGroup{
ID: g.ID,
Title: g.Title,
Description: g.Description,
Rank: g.Rank,
CreatedAt: g.CreatedAt,
UpdatedAt: g.UpdatedAt,
}
}
func NewCompliancePortalCommitmentGroupEdge(
g *coredata.CompliancePortalCommitmentGroup,
orderBy coredata.CompliancePortalCommitmentGroupOrderField,
) *CompliancePortalCommitmentGroupEdge {
return &CompliancePortalCommitmentGroupEdge{
Cursor: g.CursorKey(orderBy),
Node: NewCompliancePortalCommitmentGroup(g),
}
}
func NewCompliancePortalCommitmentGroupConnection(
p *page.Page[*coredata.CompliancePortalCommitmentGroup, coredata.CompliancePortalCommitmentGroupOrderField],
parentID gid.GID,
) *CompliancePortalCommitmentGroupConnection {
edges := make([]*CompliancePortalCommitmentGroupEdge, len(p.Data))
for i := range edges {
edges[i] = NewCompliancePortalCommitmentGroupEdge(p.Data[i], p.Cursor.OrderBy.Field)
}
return &CompliancePortalCommitmentGroupConnection{
Edges: edges,
PageInfo: NewPageInfo(p),
ParentID: parentID,
}
}
func NewCompliancePortalCommitment(c *coredata.CompliancePortalCommitment) *CompliancePortalCommitment {
return &CompliancePortalCommitment{
ID: c.ID,
Icon: c.Icon,
Eyebrow: c.Eyebrow,
Title: c.Title,
Description: c.Description,
Rank: c.Rank,
CreatedAt: c.CreatedAt,
UpdatedAt: c.UpdatedAt,
}
}
func NewCompliancePortalCommitmentEdge(
c *coredata.CompliancePortalCommitment,
orderBy coredata.CompliancePortalCommitmentOrderField,
) *CompliancePortalCommitmentEdge {
return &CompliancePortalCommitmentEdge{
Cursor: c.CursorKey(orderBy),
Node: NewCompliancePortalCommitment(c),
}
}
func NewCompliancePortalCommitmentConnection(
p *page.Page[*coredata.CompliancePortalCommitment, coredata.CompliancePortalCommitmentOrderField],
parentID gid.GID,
) *CompliancePortalCommitmentConnection {
edges := make([]*CompliancePortalCommitmentEdge, len(p.Data))
for i := range edges {
edges[i] = NewCompliancePortalCommitmentEdge(p.Data[i], p.Cursor.OrderBy.Field)
}
return &CompliancePortalCommitmentConnection{
Edges: edges,
PageInfo: NewPageInfo(p),
ParentID: parentID,
}
}

View File

@@ -47,6 +47,13 @@ type TrustCenter implements Node {
before: CursorKey
): TrustCenterReferenceConnection! @goField(forceResolver: true)
commitmentGroups(
first: Int
after: CursorKey
last: Int
before: CursorKey
): CompliancePortalCommitmentGroupConnection! @goField(forceResolver: true)
trustCenterFiles(
first: Int
after: CursorKey
@@ -304,6 +311,91 @@ type TrustCenterReferenceEdge @nda {
node: TrustCenterReference!
}
enum CompliancePortalCommitmentIcon
@goModel(model: "go.probo.inc/probo/pkg/coredata.CompliancePortalCommitmentIcon") {
LOCK_KEY
@goEnum(value: "go.probo.inc/probo/pkg/coredata.CompliancePortalCommitmentIconLockKey")
EYE_SLASH
@goEnum(value: "go.probo.inc/probo/pkg/coredata.CompliancePortalCommitmentIconEyeSlash")
FINGERPRINT
@goEnum(value: "go.probo.inc/probo/pkg/coredata.CompliancePortalCommitmentIconFingerprint")
SHIELD_WARNING
@goEnum(value: "go.probo.inc/probo/pkg/coredata.CompliancePortalCommitmentIconShieldWarning")
SHIELD_CHECK
@goEnum(value: "go.probo.inc/probo/pkg/coredata.CompliancePortalCommitmentIconShieldCheck")
SIREN
@goEnum(value: "go.probo.inc/probo/pkg/coredata.CompliancePortalCommitmentIconSiren")
KEY
@goEnum(value: "go.probo.inc/probo/pkg/coredata.CompliancePortalCommitmentIconKey")
LOCK
@goEnum(value: "go.probo.inc/probo/pkg/coredata.CompliancePortalCommitmentIconLock")
CLOUD
@goEnum(value: "go.probo.inc/probo/pkg/coredata.CompliancePortalCommitmentIconCloud")
DATABASE
@goEnum(value: "go.probo.inc/probo/pkg/coredata.CompliancePortalCommitmentIconDatabase")
GLOBE
@goEnum(value: "go.probo.inc/probo/pkg/coredata.CompliancePortalCommitmentIconGlobe")
EYE
@goEnum(value: "go.probo.inc/probo/pkg/coredata.CompliancePortalCommitmentIconEye")
USERS
@goEnum(value: "go.probo.inc/probo/pkg/coredata.CompliancePortalCommitmentIconUsers")
CERTIFICATE
@goEnum(value: "go.probo.inc/probo/pkg/coredata.CompliancePortalCommitmentIconCertificate")
GAVEL
@goEnum(value: "go.probo.inc/probo/pkg/coredata.CompliancePortalCommitmentIconGavel")
HEARTBEAT
@goEnum(value: "go.probo.inc/probo/pkg/coredata.CompliancePortalCommitmentIconHeartbeat")
BELL
@goEnum(value: "go.probo.inc/probo/pkg/coredata.CompliancePortalCommitmentIconBell")
BUG
@goEnum(value: "go.probo.inc/probo/pkg/coredata.CompliancePortalCommitmentIconBug")
CODE
@goEnum(value: "go.probo.inc/probo/pkg/coredata.CompliancePortalCommitmentIconCode")
SERVER
@goEnum(value: "go.probo.inc/probo/pkg/coredata.CompliancePortalCommitmentIconServer")
}
type CompliancePortalCommitmentGroup implements Node {
id: ID!
title: String!
description: String!
commitments(
first: Int
after: CursorKey
last: Int
before: CursorKey
): CompliancePortalCommitmentConnection! @goField(forceResolver: true)
}
type CompliancePortalCommitmentGroupConnection {
edges: [CompliancePortalCommitmentGroupEdge!]!
pageInfo: PageInfo!
}
type CompliancePortalCommitmentGroupEdge {
cursor: CursorKey!
node: CompliancePortalCommitmentGroup!
}
type CompliancePortalCommitment implements Node {
id: ID!
icon: CompliancePortalCommitmentIcon!
eyebrow: String!
title: String!
description: String!
}
type CompliancePortalCommitmentConnection {
edges: [CompliancePortalCommitmentEdge!]!
pageInfo: PageInfo!
}
type CompliancePortalCommitmentEdge {
cursor: CursorKey!
node: CompliancePortalCommitment!
}
type TrustCenterFile implements Node @nda {
id: ID!
name: String!

View File

@@ -175,6 +175,25 @@ func (r *complianceFrameworkResolver) Framework(ctx context.Context, obj *types.
return types.NewFramework(framework), nil
}
// Commitments is the resolver for the commitments field.
func (r *compliancePortalCommitmentGroupResolver) Commitments(ctx context.Context, obj *types.CompliancePortalCommitmentGroup, first *int, after *page.CursorKey, last *int, before *page.CursorKey) (*types.CompliancePortalCommitmentConnection, error) {
compliancePage := compliancepage.CompliancePageFromContext(ctx)
scope := coredata.NewScopeFromObjectID(compliancePage.OrganizationID)
pageOrderBy := page.OrderBy[coredata.CompliancePortalCommitmentOrderField]{
Field: coredata.CompliancePortalCommitmentOrderFieldRank,
Direction: page.OrderDirectionAsc,
}
cursor := types.NewCursor(first, after, last, before, pageOrderBy)
commitmentPage, err := r.trust.CompliancePortalCommitments.ListForGroupID(ctx, scope, obj.ID, cursor)
if err != nil {
r.logger.ErrorCtx(ctx, "cannot list public compliance portal commitments", log.Error(err))
return nil, gqlutils.Internal(ctx)
}
return types.NewCompliancePortalCommitmentConnection(commitmentPage), nil
}
// Alias is the resolver for the alias field.
func (r *documentResolver) Alias(ctx context.Context, obj *types.Document) (*string, error) {
return r.ResourceAliasResolver(ctx, obj.ID)
@@ -897,6 +916,25 @@ func (r *trustCenterResolver) References(ctx context.Context, obj *types.TrustCe
return types.NewTrustCenterReferenceConnection(referencePage), nil
}
// CommitmentGroups is the resolver for the commitmentGroups field.
func (r *trustCenterResolver) CommitmentGroups(ctx context.Context, obj *types.TrustCenter, first *int, after *page.CursorKey, last *int, before *page.CursorKey) (*types.CompliancePortalCommitmentGroupConnection, error) {
compliancePage := compliancepage.CompliancePageFromContext(ctx)
scope := coredata.NewScopeFromObjectID(compliancePage.OrganizationID)
pageOrderBy := page.OrderBy[coredata.CompliancePortalCommitmentGroupOrderField]{
Field: coredata.CompliancePortalCommitmentGroupOrderFieldRank,
Direction: page.OrderDirectionAsc,
}
cursor := types.NewCursor(first, after, last, before, pageOrderBy)
groupPage, err := r.trust.CompliancePortalCommitmentGroups.ListForTrustCenterID(ctx, scope, obj.ID, cursor)
if err != nil {
r.logger.ErrorCtx(ctx, "cannot list public compliance portal commitment groups", log.Error(err))
return nil, gqlutils.Internal(ctx)
}
return types.NewCompliancePortalCommitmentGroupConnection(groupPage), nil
}
// TrustCenterFiles is the resolver for the trustCenterFiles field.
func (r *trustCenterResolver) TrustCenterFiles(ctx context.Context, obj *types.TrustCenter, first *int, after *page.CursorKey, last *int, before *page.CursorKey, filter *types.TrustCenterVisibilityFilter) (*types.TrustCenterFileConnection, error) {
compliancePage := compliancepage.CompliancePageFromContext(ctx)
@@ -1115,6 +1153,11 @@ func (r *Resolver) ComplianceFramework() schema.ComplianceFrameworkResolver {
return &complianceFrameworkResolver{r}
}
// CompliancePortalCommitmentGroup returns schema.CompliancePortalCommitmentGroupResolver implementation.
func (r *Resolver) CompliancePortalCommitmentGroup() schema.CompliancePortalCommitmentGroupResolver {
return &compliancePortalCommitmentGroupResolver{r}
}
// Document returns schema.DocumentResolver implementation.
func (r *Resolver) Document() schema.DocumentResolver { return &documentResolver{r} }
@@ -1140,13 +1183,14 @@ func (r *Resolver) TrustCenterReference() schema.TrustCenterReferenceResolver {
}
type (
auditResolver struct{ *Resolver }
auditReportResolver struct{ *Resolver }
complianceFrameworkResolver struct{ *Resolver }
documentResolver struct{ *Resolver }
frameworkResolver struct{ *Resolver }
subprocessorConnectionResolver struct{ *Resolver }
trustCenterResolver struct{ *Resolver }
trustCenterFileResolver struct{ *Resolver }
trustCenterReferenceResolver struct{ *Resolver }
auditResolver struct{ *Resolver }
auditReportResolver struct{ *Resolver }
complianceFrameworkResolver struct{ *Resolver }
compliancePortalCommitmentGroupResolver struct{ *Resolver }
documentResolver struct{ *Resolver }
frameworkResolver struct{ *Resolver }
subprocessorConnectionResolver struct{ *Resolver }
trustCenterResolver struct{ *Resolver }
trustCenterFileResolver struct{ *Resolver }
trustCenterReferenceResolver struct{ *Resolver }
)

View File

@@ -0,0 +1,94 @@
// Copyright (c) 2026 Probo Inc <hello@probo.com>.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
package types
import (
"go.probo.inc/probo/pkg/coredata"
"go.probo.inc/probo/pkg/page"
)
func NewCompliancePortalCommitmentGroup(g *coredata.CompliancePortalCommitmentGroup) *CompliancePortalCommitmentGroup {
return &CompliancePortalCommitmentGroup{
ID: g.ID,
Title: g.Title,
Description: g.Description,
}
}
func NewCompliancePortalCommitmentGroupConnection(
p *page.Page[*coredata.CompliancePortalCommitmentGroup, coredata.CompliancePortalCommitmentGroupOrderField],
) *CompliancePortalCommitmentGroupConnection {
edges := make([]*CompliancePortalCommitmentGroupEdge, len(p.Data))
for i, item := range p.Data {
edges[i] = NewCompliancePortalCommitmentGroupEdge(item, p.Cursor.OrderBy.Field)
}
return &CompliancePortalCommitmentGroupConnection{
Edges: edges,
PageInfo: NewPageInfo(p),
}
}
func NewCompliancePortalCommitmentGroupEdge(
g *coredata.CompliancePortalCommitmentGroup,
orderBy coredata.CompliancePortalCommitmentGroupOrderField,
) *CompliancePortalCommitmentGroupEdge {
return &CompliancePortalCommitmentGroupEdge{
Cursor: g.CursorKey(orderBy),
Node: NewCompliancePortalCommitmentGroup(g),
}
}
func NewCompliancePortalCommitment(c *coredata.CompliancePortalCommitment) *CompliancePortalCommitment {
return &CompliancePortalCommitment{
ID: c.ID,
Icon: c.Icon,
Eyebrow: c.Eyebrow,
Title: c.Title,
Description: c.Description,
}
}
func NewCompliancePortalCommitmentConnection(
p *page.Page[*coredata.CompliancePortalCommitment, coredata.CompliancePortalCommitmentOrderField],
) *CompliancePortalCommitmentConnection {
edges := make([]*CompliancePortalCommitmentEdge, len(p.Data))
for i, item := range p.Data {
edges[i] = NewCompliancePortalCommitmentEdge(item, p.Cursor.OrderBy.Field)
}
return &CompliancePortalCommitmentConnection{
Edges: edges,
PageInfo: NewPageInfo(p),
}
}
func NewCompliancePortalCommitmentEdge(
c *coredata.CompliancePortalCommitment,
orderBy coredata.CompliancePortalCommitmentOrderField,
) *CompliancePortalCommitmentEdge {
return &CompliancePortalCommitmentEdge{
Cursor: c.CursorKey(orderBy),
Node: NewCompliancePortalCommitment(c),
}
}