Fix measure Id missing for evidence dialog

Signed-off-by: Émile Ré <emile@getprobo.com>
This commit is contained in:
Émile Ré
2026-04-06 12:32:57 +04:00
parent acf5913d6c
commit 08847d9dc5
5 changed files with 40 additions and 26 deletions

View File

@@ -13,7 +13,7 @@
// PERFORMANCE OF THIS SOFTWARE.
import { graphql, useRefetchableFragment } from "react-relay";
import { useOutletContext } from "react-router";
import { useOutletContext, useParams } from "react-router";
import type { MeasureControlsTabFragment$key } from "#/__generated__/core/MeasureControlsTabFragment.graphql";
import { LinkedControlsCard } from "#/components/controls/LinkedControlsCard";
@@ -30,7 +30,6 @@ export const controlsFragment = graphql`
filter: { type: "ControlFilter", defaultValue: null }
)
@refetchable(queryName: "MeasureControlsTabControlsQuery") {
id
canCreateControlMeasureMapping: permission(
action: "core:control:create-measure-mapping"
)
@@ -85,8 +84,12 @@ export const attachControlMutation = graphql`
export default function MeasureControlsTab() {
const { measure } = useOutletContext<{
measure: MeasureControlsTabFragment$key & { id: string };
measure: MeasureControlsTabFragment$key;
}>();
const { measureId } = useParams<{ measureId: string }>();
if (!measureId) {
throw new Error("Missing :measureId param in route");
}
// eslint-disable-next-line relay/generated-typescript-types
const [data, refetch] = useRefetchableFragment(controlsFragment, measure);
const connectionId = data.controls.__id;
@@ -97,7 +100,7 @@ export default function MeasureControlsTab() {
const readOnly = !canLinkControl && !canUnlinkControl;
const incrementOptions = {
id: data.id,
id: measureId,
node: "controls(first:0)",
};
const [detachControl, isDetaching] = useMutationWithIncrement(
@@ -122,7 +125,7 @@ export default function MeasureControlsTab() {
controls={controls}
onDetach={detachControl}
onAttach={attachControl}
params={{ measureId: data.id }}
params={{ measureId }}
connectionId={connectionId}
refetch={refetch}
readOnly={readOnly}

View File

@@ -13,7 +13,7 @@
// PERFORMANCE OF THIS SOFTWARE.
import { graphql, useFragment } from "react-relay";
import { useOutletContext } from "react-router";
import { useOutletContext, useParams } from "react-router";
import type { MeasureDocumentsTabFragment$key } from "#/__generated__/core/MeasureDocumentsTabFragment.graphql";
import { LinkedDocumentsCard } from "#/components/documents/LinkedDocumentsCard";
@@ -68,6 +68,10 @@ export const detachDocumentMutation = graphql`
`;
export default function MeasureDocumentsTab() {
const { measureId } = useParams<{ measureId: string }>();
if (!measureId) {
throw new Error("Missing :measureId param in route");
}
const { measure } = useOutletContext<{
measure: MeasureDocumentsTabFragment$key;
}>();
@@ -108,7 +112,7 @@ export default function MeasureDocumentsTab() {
documents={documents}
onAttach={attachDocument}
onDetach={detachDocument}
params={{ measureId: data.id }}
params={{ measureId }}
connectionId={connectionId}
readOnly={readOnly}
/>

View File

@@ -60,7 +60,7 @@ export const evidencesFragment = graphql`
before: { type: "CursorKey", defaultValue: null }
last: { type: "Int", defaultValue: null }
) {
id
name
canUploadEvidence: permission(action: "core:measure:upload-evidence")
evidences(
first: $first
@@ -112,12 +112,16 @@ const deleteEvidenceMutation = graphql`
export default function MeasureEvidencesTab() {
const { measure } = useOutletContext<{
measure: MeasureEvidencesTabFragment$key & { id: string; name: string };
measure: MeasureEvidencesTabFragment$key;
}>();
const { evidenceId, snapshotId } = useParams<{
const { measureId, evidenceId, snapshotId } = useParams<{
measureId: string;
evidenceId: string;
snapshotId?: string;
}>();
if (!measureId) {
throw new Error("Missing :measureId param in route");
}
// eslint-disable-next-line relay/generated-typescript-types
const pagination = usePaginationFragment(evidencesFragment, measure);
const connectionId = pagination.data.evidences.__id;
@@ -130,7 +134,7 @@ export default function MeasureEvidencesTab() {
const dialogRef = useDialogRef();
const isSnapshotMode = Boolean(snapshotId);
usePageTitle(measure.name + " - " + __("Evidences"));
usePageTitle(pagination.data.name + " - " + __("Evidences"));
return (
<div className="space-y-6">
@@ -149,7 +153,7 @@ export default function MeasureEvidencesTab() {
<EvidenceRow
key={evidence.id}
evidenceKey={evidence}
measureId={measure.id}
measureId={measureId}
organizationId={organizationId}
connectionId={connectionId}
hideActions={isSnapshotMode}
@@ -169,11 +173,11 @@ export default function MeasureEvidencesTab() {
</SortableTable>
{evidence && (
<EvidencePreviewDialog
key={evidence?.id}
key={evidence.id}
onClose={() => {
const baseUrl = isSnapshotMode
? `/organizations/${organizationId}/snapshots/${snapshotId}/risks/measures/${measure.id}/evidences`
: `/organizations/${organizationId}/measures/${measure.id}/evidences`;
? `/organizations/${organizationId}/snapshots/${snapshotId}/risks/measures/${measureId}/evidences`
: `/organizations/${organizationId}/measures/${measureId}/evidences`;
void navigate(baseUrl);
}}
evidenceId={evidence.id}
@@ -183,7 +187,7 @@ export default function MeasureEvidencesTab() {
{!isSnapshotMode && pagination.data.canUploadEvidence && (
<CreateEvidenceDialog
ref={dialogRef}
measureId={measure.id}
measureId={measureId}
connectionId={connectionId}
/>
)}

View File

@@ -13,7 +13,7 @@
// PERFORMANCE OF THIS SOFTWARE.
import { graphql, useFragment } from "react-relay";
import { useOutletContext } from "react-router";
import { useOutletContext, useParams } from "react-router";
import type { MeasureRisksTabFragment$key } from "#/__generated__/core/MeasureRisksTabFragment.graphql";
import { LinkedRisksCard } from "#/components/risks/LinkedRisksCard";
@@ -68,8 +68,12 @@ export const detachRiskMutation = graphql`
`;
export default function MeasureRisksTab() {
const { measureId } = useParams<{ measureId: string }>();
if (!measureId) {
throw new Error("Missing :measureId param in route");
}
const { measure } = useOutletContext<{
measure: MeasureRisksTabFragment$key & { id: string };
measure: MeasureRisksTabFragment$key;
}>();
const data = useFragment(risksFragment, measure);
const connectionId = data.risks.__id;

View File

@@ -15,7 +15,7 @@
import { useTranslate } from "@probo/i18n";
import { Button, IconPlusLarge } from "@probo/ui";
import { useLazyLoadQuery } from "react-relay";
import { useOutletContext } from "react-router";
import { useParams } from "react-router";
import { graphql } from "relay-runtime";
import type { MeasureTasksTabQuery } from "#/__generated__/core/MeasureTasksTabQuery.graphql";
@@ -48,12 +48,11 @@ const tasksQuery = graphql`
export default function MeasureTasksTab() {
const { __ } = useTranslate();
const { measure } = useOutletContext<{
measure: { id: string };
}>();
const { node } = useLazyLoadQuery<MeasureTasksTabQuery>(tasksQuery, {
measureId: measure.id,
});
const { measureId } = useParams<{ measureId: string }>();
if (!measureId) {
throw new Error("Missing :measureId param in route");
}
const { node } = useLazyLoadQuery<MeasureTasksTabQuery>(tasksQuery, { measureId });
if (node.__typename !== "Measure") {
throw new Error("invalid node type");
}
@@ -63,7 +62,7 @@ export default function MeasureTasksTab() {
<div className="relative">
<TasksCard connectionId={connectionId} tasks={node.tasks.edges} />
{node.canCreateTask && (
<TaskFormDialog connection={connectionId} measureId={measure.id}>
<TaskFormDialog connection={connectionId} measureId={measureId}>
<Button
variant="secondary"
icon={IconPlusLarge}