Add measure-document linking

Introduce the ability to link measures to documents, following the
existing pattern used by controls and risks. This includes:

- Database migration for measures_documents join table
- Coredata MeasureDocument struct with insert/delete operations
- Document service methods for listing/counting by measure ID
- Measure service CreateDocumentMapping/DeleteDocumentMapping methods
- Cleanup of measure-document mappings on document archive
- GraphQL mutations, inputs, payloads, and Measure.documents field
- DocumentConnection.TotalCount support for measure resolver
- MCP linkMeasure/unlinkMeasure updated to support documents
- MCP listMeasureDocuments tool
- Frontend MeasureDocumentsTab with LinkedDocumentsCard integration
- Authorization actions for measure document mapping
- E2e tests for measure document mapping

Signed-off-by: Sacha Al Himdani <sacha@getprobo.com>
This commit is contained in:
Sacha Al Himdani
2026-04-03 09:38:38 +02:00
parent 8de7add203
commit ef2e99d86c
16 changed files with 903 additions and 50 deletions

View File

@@ -19,8 +19,6 @@ import type { MeasureGraphDeleteMutation } from "#/__generated__/core/MeasureGra
import { useMutationWithToasts } from "../useMutationWithToasts";
/* eslint-disable relay/unused-fields, relay/must-colocate-fragment-spreads */
export const MeasureConnectionKey = "MeasuresPage_measures";
const deleteMeasureMutation = graphql`
@@ -46,36 +44,6 @@ export function useDeleteMeasureMutation() {
);
}
export const measureNodeQuery = graphql`
query MeasureGraphNodeQuery($measureId: ID!) {
node(id: $measureId) {
... on Measure {
id
name
description
state
category
canUpdate: permission(action: "core:measure:update")
canDelete: permission(action: "core:measure:delete")
canListTasks: permission(action: "core:task:list")
evidencesInfos: evidences(first: 0) {
totalCount
}
risksInfos: risks(first: 0) {
totalCount
}
controlsInfos: controls(first: 0) {
totalCount
}
...MeasureRisksTabFragment
...MeasureControlsTabFragment
...MeasureFormDialogMeasureFragment
...MeasureEvidencesTabFragment
}
}
}
`;
const measureUpdateMutation = graphql`
mutation MeasureGraphUpdateMutation($input: UpdateMeasureInput!) {
updateMeasure(input: $input) {