Populate subprocessor filters from server facets
The subprocessors toolbar derived its category and region filter options client-side from a second, unfiltered subprocessors(first: 250) fetch, shipping up to 250 rows purely to compute two small facet sets and silently capping the options at that limit. Expose subprocessorCategories and subprocessorCountries on TrustCenter, each backed by a DISTINCT query over the organization's third parties scoped to show_on_trust_center, and read them directly in the toolbar. The page now issues one filtered list query plus two tiny arrays, and the options only ever include values that can actually return results. Signed-off-by: Émile Ré <emile@probo.com>
This commit is contained in:
@@ -780,6 +780,78 @@ WHERE
|
||||
return count, nil
|
||||
}
|
||||
|
||||
func (v *ThirdParties) LoadDistinctTrustCenterCategoriesByOrganizationID(
|
||||
ctx context.Context,
|
||||
conn pg.Querier,
|
||||
scope Scoper,
|
||||
organizationID gid.GID,
|
||||
) ([]ThirdPartyCategory, error) {
|
||||
q := `
|
||||
SELECT DISTINCT
|
||||
category
|
||||
FROM
|
||||
third_parties
|
||||
WHERE
|
||||
%s
|
||||
AND organization_id = @organization_id
|
||||
AND show_on_trust_center = true
|
||||
ORDER BY
|
||||
category ASC
|
||||
`
|
||||
q = fmt.Sprintf(q, scope.SQLFragment())
|
||||
|
||||
args := pgx.NamedArgs{"organization_id": organizationID}
|
||||
maps.Copy(args, scope.SQLArguments())
|
||||
|
||||
rows, err := conn.Query(ctx, q, args)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cannot query thirdParty categories: %w", err)
|
||||
}
|
||||
|
||||
categories, err := pgx.CollectRows(rows, pgx.RowTo[ThirdPartyCategory])
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cannot collect thirdParty categories: %w", err)
|
||||
}
|
||||
|
||||
return categories, nil
|
||||
}
|
||||
|
||||
func (v *ThirdParties) LoadDistinctTrustCenterCountriesByOrganizationID(
|
||||
ctx context.Context,
|
||||
conn pg.Querier,
|
||||
scope Scoper,
|
||||
organizationID gid.GID,
|
||||
) ([]CountryCode, error) {
|
||||
q := `
|
||||
SELECT DISTINCT
|
||||
unnest(countries) AS country
|
||||
FROM
|
||||
third_parties
|
||||
WHERE
|
||||
%s
|
||||
AND organization_id = @organization_id
|
||||
AND show_on_trust_center = true
|
||||
ORDER BY
|
||||
country ASC
|
||||
`
|
||||
q = fmt.Sprintf(q, scope.SQLFragment())
|
||||
|
||||
args := pgx.NamedArgs{"organization_id": organizationID}
|
||||
maps.Copy(args, scope.SQLArguments())
|
||||
|
||||
rows, err := conn.Query(ctx, q, args)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cannot query thirdParty countries: %w", err)
|
||||
}
|
||||
|
||||
countries, err := pgx.CollectRows(rows, pgx.RowTo[CountryCode])
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cannot collect thirdParty countries: %w", err)
|
||||
}
|
||||
|
||||
return countries, nil
|
||||
}
|
||||
|
||||
func (v *ThirdParties) LoadByOrganizationID(
|
||||
ctx context.Context,
|
||||
conn pg.Querier,
|
||||
|
||||
@@ -33,6 +33,11 @@ type TrustCenter implements Node {
|
||||
filter: SubprocessorFilter
|
||||
): SubprocessorConnection! @goField(forceResolver: true)
|
||||
|
||||
subprocessorCategories: [SubprocessorCategory!]!
|
||||
@goField(forceResolver: true)
|
||||
|
||||
subprocessorCountries: [CountryCode!]! @goField(forceResolver: true)
|
||||
|
||||
references(
|
||||
first: Int
|
||||
after: CursorKey
|
||||
|
||||
@@ -831,6 +831,34 @@ func (r *trustCenterResolver) Subprocessors(ctx context.Context, obj *types.Trus
|
||||
return types.NewSubprocessorConnection(thirdPartyPage, r, obj.ID, thirdPartyFilter), nil
|
||||
}
|
||||
|
||||
// SubprocessorCategories is the resolver for the subprocessorCategories field.
|
||||
func (r *trustCenterResolver) SubprocessorCategories(ctx context.Context, obj *types.TrustCenter) ([]coredata.ThirdPartyCategory, error) {
|
||||
compliancePage := compliancepage.CompliancePageFromContext(ctx)
|
||||
scope := coredata.NewScopeFromObjectID(compliancePage.OrganizationID)
|
||||
|
||||
categories, err := r.trust.ThirdParties.ListDistinctTrustCenterCategoriesForOrganizationID(ctx, scope, obj.Organization.ID)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot list subprocessor categories", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return categories, nil
|
||||
}
|
||||
|
||||
// SubprocessorCountries is the resolver for the subprocessorCountries field.
|
||||
func (r *trustCenterResolver) SubprocessorCountries(ctx context.Context, obj *types.TrustCenter) ([]coredata.CountryCode, error) {
|
||||
compliancePage := compliancepage.CompliancePageFromContext(ctx)
|
||||
scope := coredata.NewScopeFromObjectID(compliancePage.OrganizationID)
|
||||
|
||||
countries, err := r.trust.ThirdParties.ListDistinctTrustCenterCountriesForOrganizationID(ctx, scope, obj.Organization.ID)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot list subprocessor countries", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return countries, nil
|
||||
}
|
||||
|
||||
// References is the resolver for the references field.
|
||||
func (r *trustCenterResolver) References(ctx context.Context, obj *types.TrustCenter, first *int, after *page.CursorKey, last *int, before *page.CursorKey) (*types.TrustCenterReferenceConnection, error) {
|
||||
compliancePage := compliancepage.CompliancePageFromContext(ctx)
|
||||
|
||||
@@ -80,6 +80,64 @@ func (s ThirdPartyService) ListForOrganizationId(
|
||||
return page.NewPage(thirdParties, cursor), nil
|
||||
}
|
||||
|
||||
func (s ThirdPartyService) ListDistinctTrustCenterCategoriesForOrganizationID(
|
||||
ctx context.Context,
|
||||
scope coredata.Scoper,
|
||||
organizationID gid.GID,
|
||||
) ([]coredata.ThirdPartyCategory, error) {
|
||||
var categories []coredata.ThirdPartyCategory
|
||||
|
||||
err := s.svc.pg.WithConn(
|
||||
ctx,
|
||||
func(ctx context.Context, conn pg.Querier) error {
|
||||
thirdParties := &coredata.ThirdParties{}
|
||||
|
||||
result, err := thirdParties.LoadDistinctTrustCenterCategoriesByOrganizationID(ctx, conn, scope, organizationID)
|
||||
if err != nil {
|
||||
return fmt.Errorf("cannot load thirdParty categories: %w", err)
|
||||
}
|
||||
|
||||
categories = result
|
||||
|
||||
return nil
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return categories, nil
|
||||
}
|
||||
|
||||
func (s ThirdPartyService) ListDistinctTrustCenterCountriesForOrganizationID(
|
||||
ctx context.Context,
|
||||
scope coredata.Scoper,
|
||||
organizationID gid.GID,
|
||||
) ([]coredata.CountryCode, error) {
|
||||
var countries []coredata.CountryCode
|
||||
|
||||
err := s.svc.pg.WithConn(
|
||||
ctx,
|
||||
func(ctx context.Context, conn pg.Querier) error {
|
||||
thirdParties := &coredata.ThirdParties{}
|
||||
|
||||
result, err := thirdParties.LoadDistinctTrustCenterCountriesByOrganizationID(ctx, conn, scope, organizationID)
|
||||
if err != nil {
|
||||
return fmt.Errorf("cannot load thirdParty countries: %w", err)
|
||||
}
|
||||
|
||||
countries = result
|
||||
|
||||
return nil
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return countries, nil
|
||||
}
|
||||
|
||||
func (s ThirdPartyService) CountForTrustCenterId(
|
||||
ctx context.Context,
|
||||
scope coredata.Scoper,
|
||||
|
||||
Reference in New Issue
Block a user