From 83445c6e340551e80cc301cb5f5967214671f2b8 Mon Sep 17 00:00:00 2001 From: Sacha Al Himdani Date: Fri, 22 May 2026 10:55:31 +0200 Subject: [PATCH] Fix signature count mismatch with signatures tab on documents The badge on a document version showed signatures filtered by activeContract: true, while the signatures tab fetched signatures with no filter and listed people filtered by contractEnded: false and state: ACTIVE. The two views disagreed both when a signer's contract had ended and when a signer was deactivated while still under contract. Add a state: ProfileState field to DocumentVersionSignatureFilter alongside the existing activeContract filter, so the signature query can mirror the same predicates as the people query. Pass { activeContract: true, state: ACTIVE } from the badge, the document list item, and the signatures tab fragment. The same filter is now evaluated on both the count and the list. Threaded through the console and MCP resolvers, the MCP spec, and the n8n getAllSignatures operation. Signed-off-by: Sacha Al Himdani --- .../organizations/documents/DocumentLayout.tsx | 8 ++++---- .../documents/_components/DocumentListItem.tsx | 4 ++-- .../_components/DocumentSignatureList.tsx | 9 ++++++--- .../document/getAllSignatures.operation.ts | 13 +++++++++++++ .../document_version_signature_filter.go | 16 +++++++++++++++- pkg/server/api/console/v1/document_resolvers.go | 7 ++++++- .../api/console/v1/graphql/document.graphql | 1 + pkg/server/api/mcp/v1/schema.resolvers.go | 7 ++++++- pkg/server/api/mcp/v1/specification.yaml | 3 +++ 9 files changed, 56 insertions(+), 12 deletions(-) diff --git a/apps/console/src/pages/organizations/documents/DocumentLayout.tsx b/apps/console/src/pages/organizations/documents/DocumentLayout.tsx index ec1e5b077..3735dd7b8 100644 --- a/apps/console/src/pages/organizations/documents/DocumentLayout.tsx +++ b/apps/console/src/pages/organizations/documents/DocumentLayout.tsx @@ -40,10 +40,10 @@ export const documentLayoutQuery = graphql` ...DocumentTitleFormFragment ...DocumentActionsDropdown_versionFragment ...DocumentDetailsCard_versionFragment - signatures(first: 0 filter: { activeContract: true }) { + signatures(first: 0 filter: { activeContract: true, state: ACTIVE }) { totalCount } - signedSignatures: signatures(first: 0 filter: { states: [SIGNED], activeContract: true }) { + signedSignatures: signatures(first: 0 filter: { states: [SIGNED], activeContract: true, state: ACTIVE }) { totalCount } approvalQuorums(first: 1, orderBy: { field: CREATED_AT, direction: DESC }) { @@ -85,10 +85,10 @@ export const documentLayoutQuery = graphql` ...DocumentTitleFormFragment ...DocumentActionsDropdown_versionFragment ...DocumentDetailsCard_versionFragment - signatures(first: 0 filter: { activeContract: true }) { + signatures(first: 0 filter: { activeContract: true, state: ACTIVE }) { totalCount } - signedSignatures: signatures(first: 0 filter: { states: [SIGNED], activeContract: true }) { + signedSignatures: signatures(first: 0 filter: { states: [SIGNED], activeContract: true, state: ACTIVE }) { totalCount } approvalQuorums(first: 1, orderBy: { field: CREATED_AT, direction: DESC }) { diff --git a/apps/console/src/pages/organizations/documents/_components/DocumentListItem.tsx b/apps/console/src/pages/organizations/documents/_components/DocumentListItem.tsx index c170b396e..f87552d40 100644 --- a/apps/console/src/pages/organizations/documents/_components/DocumentListItem.tsx +++ b/apps/console/src/pages/organizations/documents/_components/DocumentListItem.tsx @@ -54,10 +54,10 @@ const fragment = graphql` } } } - signatures(first: 0 filter: { activeContract: true }) { + signatures(first: 0 filter: { activeContract: true, state: ACTIVE }) { totalCount } - signedSignatures: signatures(first: 0 filter: { states: [SIGNED], activeContract: true }) { + signedSignatures: signatures(first: 0 filter: { states: [SIGNED], activeContract: true, state: ACTIVE }) { totalCount } } diff --git a/apps/console/src/pages/organizations/documents/signatures/_components/DocumentSignatureList.tsx b/apps/console/src/pages/organizations/documents/signatures/_components/DocumentSignatureList.tsx index f56f86abe..1edc4880c 100644 --- a/apps/console/src/pages/organizations/documents/signatures/_components/DocumentSignatureList.tsx +++ b/apps/console/src/pages/organizations/documents/signatures/_components/DocumentSignatureList.tsx @@ -29,7 +29,7 @@ const versionFragment = graphql` @argumentDefinitions( count: { type: "Int", defaultValue: 1000 } cursor: { type: "CursorKey" } - signatureFilter: { type: "DocumentVersionSignatureFilter" } + signatureFilter: { type: "DocumentVersionSignatureFilter", defaultValue: { activeContract: true, state: ACTIVE } } ) { ...DocumentSignaturePlaceholder_versionFragment signatures(first: $count, after: $cursor, filter: $signatureFilter) @@ -102,8 +102,11 @@ export function DocumentSignatureList(props: { return; } - const filter - = selectedStates.length > 0 ? { states: selectedStates } : null; + const filter = { + activeContract: true, + state: "ACTIVE" as const, + ...(selectedStates.length > 0 ? { states: selectedStates } : {}), + }; refetch({ signatureFilter: filter }); }, [selectedStates, refetch]); diff --git a/packages/n8n-node/nodes/Probo/actions/document/getAllSignatures.operation.ts b/packages/n8n-node/nodes/Probo/actions/document/getAllSignatures.operation.ts index 75013a91f..872718910 100644 --- a/packages/n8n-node/nodes/Probo/actions/document/getAllSignatures.operation.ts +++ b/packages/n8n-node/nodes/Probo/actions/document/getAllSignatures.operation.ts @@ -91,6 +91,18 @@ export const description: INodeProperties[] = [ default: false, description: 'Whether to filter by active contract status', }, + { + displayName: 'Profile State', + name: 'state', + type: 'options', + default: '', + description: 'Filter by signatory profile state', + options: [ + { name: 'Any', value: '' }, + { name: 'Active', value: 'ACTIVE' }, + { name: 'Inactive', value: 'INACTIVE' }, + ], + }, ], }, ]; @@ -107,6 +119,7 @@ export async function execute( const filter: IDataObject = {}; if ((filters.states as string[])?.length) filter.states = filters.states; if (filters.activeContract !== undefined) filter.activeContract = filters.activeContract; + if (filters.state) filter.state = filters.state; const hasFilter = Object.keys(filter).length > 0; diff --git a/pkg/coredata/document_version_signature_filter.go b/pkg/coredata/document_version_signature_filter.go index 414ef7ec4..61b673562 100644 --- a/pkg/coredata/document_version_signature_filter.go +++ b/pkg/coredata/document_version_signature_filter.go @@ -22,13 +22,15 @@ type ( DocumentVersionSignatureFilter struct { states DocumentVersionSignatureStates activeContract *bool + state *ProfileState } ) -func NewDocumentVersionSignatureFilter(states []DocumentVersionSignatureState, activeContract *bool) *DocumentVersionSignatureFilter { +func NewDocumentVersionSignatureFilter(states []DocumentVersionSignatureState, activeContract *bool, state *ProfileState) *DocumentVersionSignatureFilter { return &DocumentVersionSignatureFilter{ states: DocumentVersionSignatureStates(states), activeContract: activeContract, + state: state, } } @@ -36,6 +38,7 @@ func (f *DocumentVersionSignatureFilter) SQLArguments() pgx.StrictNamedArgs { return pgx.StrictNamedArgs{ "states": f.states, "active_contract": f.activeContract, + "profile_state": f.state, } } @@ -70,5 +73,16 @@ func (f *DocumentVersionSignatureFilter) SQLFragment() string { ) ) END + AND + CASE + WHEN @profile_state::text IS NULL + THEN TRUE + ELSE EXISTS ( + SELECT 1 + FROM iam_membership_profiles p + WHERE p.id = signed_by_profile_id + AND p.state = @profile_state::membership_state + ) + END )` } diff --git a/pkg/server/api/console/v1/document_resolvers.go b/pkg/server/api/console/v1/document_resolvers.go index 666bad200..f6b4e191c 100644 --- a/pkg/server/api/console/v1/document_resolvers.go +++ b/pkg/server/api/console/v1/document_resolvers.go @@ -279,6 +279,7 @@ func (r *documentVersionResolver) Signatures(ctx context.Context, obj *types.Doc var ( signatureStates []coredata.DocumentVersionSignatureState activeContract *bool + profileState *coredata.ProfileState ) if filter != nil { @@ -289,9 +290,13 @@ func (r *documentVersionResolver) Signatures(ctx context.Context, obj *types.Doc if filter.ActiveContract != nil { activeContract = filter.ActiveContract } + + if filter.State != nil { + profileState = filter.State + } } - signatureFilter := coredata.NewDocumentVersionSignatureFilter(signatureStates, activeContract) + signatureFilter := coredata.NewDocumentVersionSignatureFilter(signatureStates, activeContract, profileState) cursor := types.NewCursor(first, after, last, before, pageOrderBy) diff --git a/pkg/server/api/console/v1/graphql/document.graphql b/pkg/server/api/console/v1/graphql/document.graphql index 6054786be..1afcd6827 100644 --- a/pkg/server/api/console/v1/graphql/document.graphql +++ b/pkg/server/api/console/v1/graphql/document.graphql @@ -247,6 +247,7 @@ input DocumentVersionSignatureOrder { input DocumentVersionSignatureFilter { states: [DocumentVersionSignatureState!] activeContract: Boolean + state: ProfileState } input DocumentVersionApprovalQuorumOrder { diff --git a/pkg/server/api/mcp/v1/schema.resolvers.go b/pkg/server/api/mcp/v1/schema.resolvers.go index a06910121..5e6c919da 100644 --- a/pkg/server/api/mcp/v1/schema.resolvers.go +++ b/pkg/server/api/mcp/v1/schema.resolvers.go @@ -2188,6 +2188,7 @@ func (r *Resolver) ListDocumentVersionSignaturesTool(ctx context.Context, req *m var ( signatureStates []coredata.DocumentVersionSignatureState activeContract *bool + profileState *coredata.ProfileState ) if input.Filter != nil { @@ -2198,9 +2199,13 @@ func (r *Resolver) ListDocumentVersionSignaturesTool(ctx context.Context, req *m if input.Filter.ActiveContract != nil { activeContract = input.Filter.ActiveContract } + + if input.Filter.State != nil { + profileState = input.Filter.State + } } - signatureFilter := coredata.NewDocumentVersionSignatureFilter(signatureStates, activeContract) + signatureFilter := coredata.NewDocumentVersionSignatureFilter(signatureStates, activeContract, profileState) page, err := prb.Documents.ListSignatures(ctx, scope, input.DocumentVersionID, cursor, signatureFilter) if err != nil { diff --git a/pkg/server/api/mcp/v1/specification.yaml b/pkg/server/api/mcp/v1/specification.yaml index 5affd51a8..f938a5b4f 100644 --- a/pkg/server/api/mcp/v1/specification.yaml +++ b/pkg/server/api/mcp/v1/specification.yaml @@ -6322,6 +6322,9 @@ components: active_contract: type: boolean description: Signatory contract status + state: + $ref: "#/components/schemas/ProfileState" + description: Signatory profile state ListDocumentVersionSignaturesOutput: type: object