diff --git a/packages/n8n-node/nodes/Probo/actions/document/getAll.operation.ts b/packages/n8n-node/nodes/Probo/actions/document/getAll.operation.ts index f9691f234..2ce132438 100644 --- a/packages/n8n-node/nodes/Probo/actions/document/getAll.operation.ts +++ b/packages/n8n-node/nodes/Probo/actions/document/getAll.operation.ts @@ -60,6 +60,70 @@ export const description: INodeProperties[] = [ default: 50, description: 'Max number of results to return', }, + { + displayName: 'Filters', + name: 'filters', + type: 'collection', + placeholder: 'Add Filter', + default: {}, + displayOptions: { + show: { + resource: ['document'], + operation: ['getAll'], + }, + }, + options: [ + { + displayName: 'Query', + name: 'query', + type: 'string', + default: '', + description: 'Search query to filter documents', + }, + { + displayName: 'Document Types', + name: 'documentTypes', + type: 'multiOptions', + default: [], + description: 'Filter by document type', + options: [ + { name: 'Governance', value: 'GOVERNANCE' }, + { name: 'Other', value: 'OTHER' }, + { name: 'Plan', value: 'PLAN' }, + { name: 'Policy', value: 'POLICY' }, + { name: 'Procedure', value: 'PROCEDURE' }, + { name: 'Record', value: 'RECORD' }, + { name: 'Register', value: 'REGISTER' }, + { name: 'Report', value: 'REPORT' }, + { name: 'Template', value: 'TEMPLATE' }, + ], + }, + { + displayName: 'Classifications', + name: 'classifications', + type: 'multiOptions', + default: [], + description: 'Filter by document classification', + options: [ + { name: 'Confidential', value: 'CONFIDENTIAL' }, + { name: 'Internal', value: 'INTERNAL' }, + { name: 'Public', value: 'PUBLIC' }, + { name: 'Secret', value: 'SECRET' }, + ], + }, + { + displayName: 'Status', + name: 'status', + type: 'multiOptions', + default: [], + description: 'Filter by document status', + options: [ + { name: 'Active', value: 'ACTIVE' }, + { name: 'Archived', value: 'ARCHIVED' }, + ], + }, + ], + }, ]; export async function execute( @@ -69,12 +133,19 @@ export async function execute( const organizationId = this.getNodeParameter('organizationId', itemIndex) as string; const returnAll = this.getNodeParameter('returnAll', itemIndex) as boolean; const limit = this.getNodeParameter('limit', itemIndex, 50) as number; + const filters = this.getNodeParameter('filters', itemIndex, {}) as IDataObject; + + const filter: IDataObject = {}; + if (filters.query) filter.query = filters.query; + if ((filters.documentTypes as string[])?.length) filter.documentTypes = filters.documentTypes; + if ((filters.classifications as string[])?.length) filter.classifications = filters.classifications; + filter.status = (filters.status as string[])?.length ? filters.status : ['ACTIVE']; const query = ` - query GetDocuments($organizationId: ID!, $first: Int, $after: CursorKey) { + query GetDocuments($organizationId: ID!, $first: Int, $after: CursorKey, $filter: DocumentFilter) { node(id: $organizationId) { ... on Organization { - documents(first: $first, after: $after) { + documents(first: $first, after: $after, filter: $filter) { edges { node { id @@ -97,10 +168,12 @@ export async function execute( } `; + const variables: IDataObject = { organizationId, filter }; + const documents = await proboApiRequestAllItems.call( this, query, - { organizationId }, + variables, (response) => { const data = response?.data as IDataObject | undefined; const node = data?.node as IDataObject | undefined; 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 6ea81e9f8..72b9c1f6b 100644 --- a/packages/n8n-node/nodes/Probo/actions/document/getAllSignatures.operation.ts +++ b/packages/n8n-node/nodes/Probo/actions/document/getAllSignatures.operation.ts @@ -60,6 +60,39 @@ export const description: INodeProperties[] = [ default: 50, description: 'Max number of results to return', }, + { + displayName: 'Filters', + name: 'filters', + type: 'collection', + placeholder: 'Add Filter', + default: {}, + displayOptions: { + show: { + resource: ['document'], + operation: ['getAllSignatures'], + }, + }, + options: [ + { + displayName: 'States', + name: 'states', + type: 'multiOptions', + default: [], + description: 'Filter by signature state', + options: [ + { name: 'Requested', value: 'REQUESTED' }, + { name: 'Signed', value: 'SIGNED' }, + ], + }, + { + displayName: 'Active Contract', + name: 'activeContract', + type: 'boolean', + default: false, + description: 'Whether to filter by active contract status', + }, + ], + }, ]; export async function execute( @@ -69,12 +102,19 @@ export async function execute( const documentVersionId = this.getNodeParameter('documentVersionId', itemIndex) as string; const returnAll = this.getNodeParameter('returnAll', itemIndex) as boolean; const limit = this.getNodeParameter('limit', itemIndex, 50) as number; + const filters = this.getNodeParameter('filters', itemIndex, {}) as IDataObject; + + const filter: IDataObject = {}; + if ((filters.states as string[])?.length) filter.states = filters.states; + if (filters.activeContract !== undefined) filter.activeContract = filters.activeContract; + + const hasFilter = Object.keys(filter).length > 0; const query = ` - query GetDocumentVersionSignatures($documentVersionId: ID!, $first: Int, $after: CursorKey) { + query GetDocumentVersionSignatures($documentVersionId: ID!, $first: Int, $after: CursorKey${hasFilter ? ', $filter: DocumentVersionSignatureFilter' : ''}) { node(id: $documentVersionId) { ... on DocumentVersion { - signatures(first: $first, after: $after) { + signatures(first: $first, after: $after${hasFilter ? ', filter: $filter' : ''}) { edges { node { id @@ -100,10 +140,13 @@ export async function execute( } `; + const variables: IDataObject = { documentVersionId }; + if (hasFilter) variables.filter = filter; + const signatures = await proboApiRequestAllItems.call( this, query, - { documentVersionId }, + variables, (response) => { const data = response?.data as IDataObject | undefined; const node = data?.node as IDataObject | undefined; diff --git a/packages/n8n-node/nodes/Probo/actions/document/getAllVersions.operation.ts b/packages/n8n-node/nodes/Probo/actions/document/getAllVersions.operation.ts index 5a8e36609..c954764d4 100644 --- a/packages/n8n-node/nodes/Probo/actions/document/getAllVersions.operation.ts +++ b/packages/n8n-node/nodes/Probo/actions/document/getAllVersions.operation.ts @@ -60,6 +60,33 @@ export const description: INodeProperties[] = [ default: 50, description: 'Max number of results to return', }, + { + displayName: 'Filters', + name: 'filters', + type: 'collection', + placeholder: 'Add Filter', + default: {}, + displayOptions: { + show: { + resource: ['document'], + operation: ['getAllVersions'], + }, + }, + options: [ + { + displayName: 'Statuses', + name: 'statuses', + type: 'multiOptions', + default: [], + description: 'Filter by version status', + options: [ + { name: 'Draft', value: 'DRAFT' }, + { name: 'Pending Approval', value: 'PENDING_APPROVAL' }, + { name: 'Published', value: 'PUBLISHED' }, + ], + }, + ], + }, ]; export async function execute( @@ -69,12 +96,18 @@ export async function execute( const documentId = this.getNodeParameter('documentId', itemIndex) as string; const returnAll = this.getNodeParameter('returnAll', itemIndex) as boolean; const limit = this.getNodeParameter('limit', itemIndex, 50) as number; + const filters = this.getNodeParameter('filters', itemIndex, {}) as IDataObject; + + const filter: IDataObject = {}; + if ((filters.statuses as string[])?.length) filter.statuses = filters.statuses; + + const hasFilter = Object.keys(filter).length > 0; const query = ` - query GetDocumentVersions($documentId: ID!, $first: Int, $after: CursorKey) { + query GetDocumentVersions($documentId: ID!, $first: Int, $after: CursorKey${hasFilter ? ', $filter: DocumentVersionFilter' : ''}) { node(id: $documentId) { ... on Document { - versions(first: $first, after: $after) { + versions(first: $first, after: $after${hasFilter ? ', filter: $filter' : ''}) { edges { node { id @@ -101,10 +134,13 @@ export async function execute( } `; + const variables: IDataObject = { documentId }; + if (hasFilter) variables.filter = filter; + const versions = await proboApiRequestAllItems.call( this, query, - { documentId }, + variables, (response) => { const data = response?.data as IDataObject | undefined; const node = data?.node as IDataObject | undefined; diff --git a/pkg/server/api/mcp/v1/schema.resolvers.go b/pkg/server/api/mcp/v1/schema.resolvers.go index f43672cab..d9df970f5 100644 --- a/pkg/server/api/mcp/v1/schema.resolvers.go +++ b/pkg/server/api/mcp/v1/schema.resolvers.go @@ -2036,7 +2036,8 @@ func (r *Resolver) ListDocumentsTool(ctx context.Context, req *mcp.CallToolReque cursor := types.NewCursor(input.Size, input.Cursor, pageOrderBy) - documentFilter := coredata.NewDocumentFilter(nil) + documentFilter := coredata.NewDocumentFilter(nil). + WithStatus([]coredata.DocumentStatus{coredata.DocumentStatusActive}) if input.Filter != nil { var query *string if input.Filter.Query != nil && *input.Filter.Query != "" { @@ -2045,7 +2046,12 @@ func (r *Resolver) ListDocumentsTool(ctx context.Context, req *mcp.CallToolReque documentFilter = coredata.NewDocumentFilter(query). WithDocumentTypes(input.Filter.DocumentTypes). - WithClassifications(input.Filter.Classifications) + WithClassifications(input.Filter.Classifications). + WithStatus(input.Filter.Status) + + if len(input.Filter.Status) == 0 { + documentFilter = documentFilter.WithStatus([]coredata.DocumentStatus{coredata.DocumentStatusActive}) + } } docPage, err := prb.Documents.ListByOrganizationID(ctx, input.OrganizationID, cursor, documentFilter) @@ -2168,7 +2174,12 @@ func (r *Resolver) ListDocumentVersionsTool(ctx context.Context, req *mcp.CallTo cursor := types.NewCursor(input.Size, input.Cursor, pageOrderBy) svc := r.ProboService(ctx, input.DocumentID) - versionPage, err := svc.Documents.ListVersions(ctx, input.DocumentID, cursor, coredata.NewDocumentVersionFilter()) + versionFilter := coredata.NewDocumentVersionFilter() + if input.Filter != nil && len(input.Filter.Statuses) > 0 { + versionFilter = versionFilter.WithStatuses(input.Filter.Statuses...) + } + + versionPage, err := svc.Documents.ListVersions(ctx, input.DocumentID, cursor, versionFilter) if err != nil { panic(fmt.Errorf("cannot list document versions: %w", err)) } diff --git a/pkg/server/api/mcp/v1/specification.yaml b/pkg/server/api/mcp/v1/specification.yaml index 164bbeb11..144de2845 100644 --- a/pkg/server/api/mcp/v1/specification.yaml +++ b/pkg/server/api/mcp/v1/specification.yaml @@ -5181,6 +5181,7 @@ components: type: string enum: - CREATED_AT + - UPDATED_AT - TITLE - DOCUMENT_TYPE go.probo.inc/mcpgen/type: go.probo.inc/probo/pkg/coredata.DocumentOrderField @@ -5433,6 +5434,11 @@ components: items: $ref: "#/components/schemas/DocumentClassification" description: Document classifications + status: + type: array + items: + $ref: "#/components/schemas/DocumentStatus" + description: Document statuses ListDocumentsOutput: type: object @@ -5616,6 +5622,14 @@ components: cursor: $ref: "#/components/schemas/CursorKey" description: Page cursor + filter: + type: object + properties: + statuses: + type: array + items: + $ref: "#/components/schemas/DocumentVersionStatus" + description: Document version statuses ListDocumentVersionsOutput: type: object @@ -8327,7 +8341,7 @@ tools: outputSchema: $ref: "#/components/schemas/TakeSnapshotOutput" - name: listDocuments - description: List all documents for the organization + description: List documents for the organization. By default only ACTIVE documents are returned; pass status filter to include ARCHIVED. hints: readonly: true idempotent: true