Skip to content

feat: support showing risks from evidence - #282

Merged
gusfcarvalho merged 2 commits into
mainfrom
gc-evidence-form-risks
Jul 13, 2026
Merged

feat: support showing risks from evidence#282
gusfcarvalho merged 2 commits into
mainfrom
gc-evidence-form-risks

Conversation

@gusfcarvalho

@gusfcarvalho gusfcarvalho commented Jul 13, 2026

Copy link
Copy Markdown
Contributor

feat: better evidence forms

Summary by CodeRabbit

  • New Features

    • Added editable Properties and Links sections to evidence forms, including expiry date support and updated attachment handling.
    • Added a Risks tab to evidence details with permission-aware risk creation and a Create Risk from Evidence modal with SSP selection.
    • Enhanced risk creation with Likelihood and Impact, including template hint normalization.
    • Updated lineage views to group risk nodes by owning SSP and route using the active SSP scope.
  • Bug Fixes

    • Evidence creation no longer pre-generates an identifier client-side.
    • Improved risk navigation to preserve SSP context and handle missing IDs safely.

feat: better evidence forms
Signed-off-by: Gustavo Carvalho <gustavo.carvalho@container-solutions.com>
Copilot AI review requested due to automatic review settings July 13, 2026 15:08
@coderabbitai

coderabbitai Bot commented Jul 13, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Evidence forms now support structured properties, links, expiry, and re-submission. Evidence views add lazy-loaded risk association and creation. Lineage risk nodes gain SSP-aware routing and grouped rendering ranked by risk severity.

Changes

Evidence workflows

Layer / File(s) Summary
Evidence form structure
src/components/forms/*, src/views/evidence/CreateView.vue, src/views/evidence/UpdateView.vue, src/views/evidence/partial/EvidenceForm.vue
Evidence editing adds property/link editors, expiry validation, structured payload mapping, upload-link updates, and re-submission labels.
Risk creation fields
src/components/risk/RiskCreateForm.vue
Risk creation adds normalized likelihood and impact selectors and submits the selected values.
Evidence risks tab
src/views/evidence/ViewView.vue, src/views/evidence/__tests__/ViewView.spec.ts
Evidence views load risks and SSPs on demand, display risk states and metadata, support risk creation and linking, and test loading, empty, routing, and stream-UUID cases.

SSP-aware lineage

Layer / File(s) Summary
Lineage metadata and routing
src/composables/useLineage/types.ts, src/composables/useLineage/fixtures.ts, src/components/lineage/nodeMeta.ts, src/components/lineage/__tests__/nodeMeta.spec.ts
Risk nodes expose SSP metadata, fixtures populate it, and risk routes support SSP-scoped destinations.
Risk grouping and ranking
src/views/lineage/ranking.ts, src/views/lineage/__tests__/ranking.spec.ts
Ranking utilities separate structural nodes and group SSP risks in worst-first order with fallback titles.
Lineage view rendering
src/views/lineage/LineageGraphView.vue, src/views/lineage/LineageTreeView.vue, src/views/lineage/__tests__/LineageGraphView.spec.ts
Graph and tree navigation use SSP scope, while graph rendering groups risks beneath SSP headers and tests ordering.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant EvidenceView
  participant RiskCreateForm
  participant EvidenceAPI
  EvidenceView->>EvidenceAPI: Load risks and SSP options
  EvidenceView->>RiskCreateForm: Open create-risk dialog
  RiskCreateForm->>EvidenceView: Emit created risk
  EvidenceView->>EvidenceAPI: Link risk to evidence
  EvidenceView->>EvidenceAPI: Refresh associated risks
Loading

Poem

A rabbit hops through forms so neat,
With links and risks in rows complete.
SSP groups bloom in ordered lines,
And evidence gains revision signs.
“Add and route!” the bunny sings—
New paths for paws and data wings.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 40.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: adding support for showing risks from evidence.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR enhances the UI for evidence and lineage views by (1) adding an “Associated Risks” tab and “Create Risk from Evidence” flow, and (2) improving lineage risk handling by scoping risk-detail navigation and grouping risk nodes by owning SSP.

Changes:

  • Add an Evidence “Risks” tab that loads associated risks on-demand and supports creating + linking a new risk to an evidence stream.
  • Group lineage “risk” nodes by owning SSP in the graph view and add SSP-scoped routing for risk detail navigation.
  • Improve evidence create/update UX (re-submit terminology, richer form sections, expiry date, properties/links editors).

Reviewed changes

Copilot reviewed 17 out of 17 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
src/views/lineage/ranking.ts Adds helpers to split structural nodes and bucket risk nodes into SSP groups.
src/views/lineage/LineageTreeView.vue Updates node selection routing to pass an SSP id into nodeDetailRoute.
src/views/lineage/LineageGraphView.vue Renders structural nodes + SSP risk buckets and updates detail routing calls.
src/views/lineage/tests/ranking.spec.ts Adds unit tests for structuralNodes and riskGroups.
src/views/lineage/tests/LineageGraphView.spec.ts Adds a smoke test verifying SSP risk grouping display/order.
src/views/evidence/ViewView.vue Adds “Risks” tab UI, lazy loading of risks, and risk creation/linking dialog.
src/views/evidence/UpdateView.vue Updates copy to “Re-submit Evidence” and clarifies revision semantics.
src/views/evidence/partial/EvidenceForm.vue Restructures evidence form, adds expiry, properties, and links editors; uses uuid() helper.
src/views/evidence/CreateView.vue Removes client-side UUID prefill (now generated inside form).
src/views/evidence/tests/ViewView.spec.ts Extends tests to cover risks tab behavior and PrimeVue toast setup.
src/composables/useLineage/types.ts Adds sspId/sspTitle to lineage nodes (for risk ownership).
src/composables/useLineage/fixtures.ts Populates fixture risks with sspId/sspTitle.
src/components/risk/RiskCreateForm.vue Adds likelihood/impact selection and uses them in risk creation payload.
src/components/lineage/nodeMeta.ts Extends nodeDetailRoute to optionally return SSP-scoped risk detail routes.
src/components/lineage/tests/nodeMeta.spec.ts Adds test coverage for SSP-scoped risk routing.
src/components/forms/PropsEditor.vue New editor component for OSCAL props.
src/components/forms/LinksEditor.vue New editor component for OSCAL links.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/views/lineage/LineageGraphView.vue
Comment thread src/views/lineage/LineageTreeView.vue
Comment thread src/views/lineage/ranking.ts
Comment thread src/views/evidence/ViewView.vue Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
src/views/lineage/LineageGraphView.vue (1)

300-375: 📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win

Extract the duplicated node-box template into a shared component.

The structural node box (L300-328) and the risk node box (L344-371) render identical markup — same LineageNodeRow, children/leaf indicator, details button, selection ring, and setBoxRef wiring. The only difference is the v-for source (structuralNodes(col) vs group.nodes). Future changes to node rendering will require updating both locations, risking divergence.

Extract a LineageNodeBox component accepting node, colIndex, and selectedKey as props, emitting boxClick and detailsClick events.

♻️ Proposed extraction
+ <!-- LineageNodeBox.vue -->
+ <script setup lang="ts">
+ import LineageNodeRow from '`@/components/lineage/LineageNodeRow.vue`';
+ import { nodeCardClass } from '`@/components/lineage/nodeMeta`';
+ import type { LineageNode } from '`@/composables/useLineage/types`';
+
+ defineProps<{
+   node: LineageNode;
+   colIndex: number;
+   selectedKey: string | null;
+ }>();
+
+ const emit = defineEmits<{
+   boxClick: [colIndex: number, node: LineageNode];
+   detailsClick: [node: LineageNode];
+ }>();
+ </script>
+
+ <template>
+   <div
+     class="cursor-pointer rounded-lg border border-l-4 border-surface-200 p-3 transition hover:shadow-md dark:border-surface-700"
+     :class="[
+       nodeCardClass(node),
+       selectedKey === node.key
+         ? 'ring-2 ring-primary ring-offset-1 dark:ring-offset-surface-900'
+         : '',
+     ]"
+     `@click`="emit('boxClick', colIndex, node)"
+   >
+     <LineageNodeRow :node="node" card />
+     <div
+       class="mt-1 flex items-center justify-between pl-5 text-xs text-surface-500 dark:text-surface-400"
+     >
+       <span v-if="node.hasChildren">{{ node.childrenCount }} children ›</span>
+       <span v-else class="italic">leaf</span>
+       <button
+         class="rounded px-1.5 py-0.5 hover:bg-surface-200 dark:hover:bg-surface-700"
+         `@click.stop`="emit('detailsClick', node)"
+       >
+         details
+       </button>
+     </div>
+   </div>
+ </template>

Then in LineageGraphView.vue, replace both sections:

- <div
-   v-for="node in structuralNodes(col)"
-   :key="node.key"
-   :ref="(el) => setBoxRef(i, node.key, el)"
-   class="cursor-pointer rounded-lg border border-l-4 border-surface-200 p-3 transition hover:shadow-md dark:border-surface-700"
-   :class="[
-     nodeCardClass(node),
-     col.selectedKey === node.key
-       ? 'ring-2 ring-primary ring-offset-1 dark:ring-offset-surface-900'
-       : '',
-   ]"
-   `@click`="onBoxClick(i, node)"
- >
-   <LineageNodeRow :node="node" card />
-   <div
-     class="mt-1 flex items-center justify-between pl-5 text-xs text-surface-500 dark:text-surface-400"
-   >
-     <span v-if="node.hasChildren">{{ node.childrenCount }} children ›</span>
-     <span v-else class="italic">leaf</span>
-     <button
-       class="rounded px-1.5 py-0.5 hover:bg-surface-200 dark:hover:bg-surface-700"
-       `@click.stop`="openDetails(node)"
-     >
-       details
-     </button>
-   </div>
- </div>
+ <LineageNodeBox
+   v-for="node in structuralNodes(col)"
+   :key="node.key"
+   :node="node"
+   :col-index="i"
+   :selected-key="col.selectedKey"
+   :ref="(el) => setBoxRef(i, node.key, el?.$el : null)"
+   `@box-click`="onBoxClick"
+   `@details-click`="openDetails"
+ />

And similarly for the risk node loop inside each SSP group.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/views/lineage/LineageGraphView.vue` around lines 300 - 375, Extract the
duplicated node-card markup into a shared LineageNodeBox component accepting
node, colIndex, and selectedKey props and emitting boxClick and detailsClick
events. Move the existing nodeCardClass, selection-ring class, setBoxRef wiring,
LineageNodeRow, child/leaf indicator, and details button behavior into that
component, then replace both the structuralNodes(col) and risk group.nodes
templates in LineageGraphView with it while preserving their existing loops and
event behavior.
src/components/risk/RiskCreateForm.vue (1)

302-310: 🗄️ Data Integrity & Integration | 🔵 Trivial | ⚡ Quick win

created emit is typed as OSCAL Risk, but the actual response has a different shape — forces an unsafe cast downstream.

returnedRisk (useDataApi<Risk>) and the created: [risk: Risk] emit type both claim an OSCAL Risk, but the SSP-scoped register-create endpoint actually returns a register risk with an id field. src/views/evidence/ViewView.vue's onRiskCreated has to work around this with risk as unknown as { id?: string } (documented via a comment there). Typing the response/emit against the real register-risk shape would remove the need for that cast and prevent future unsafe casts by other consumers.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/components/risk/RiskCreateForm.vue` around lines 302 - 310, Update the
register-risk creation flow in RiskCreateForm, including the useDataApi response
type and created emit payload, to use the actual register-risk shape containing
the id field rather than OSCAL Risk. Propagate that type to consumers such as
onRiskCreated so they access the typed id directly and remove the unsafe cast.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/components/forms/LinksEditor.vue`:
- Around line 50-57: Update the TertiaryButton class in LinksEditor.vue and the
corresponding button class in PropsEditor.vue to use Tailwind v4 trailing
important syntax, changing !px-1 to px-1! while preserving the existing padding
utility.

In `@src/components/lineage/nodeMeta.ts`:
- Around line 432-444: Update nodeDetailRoute’s risk branch to prefer node.sspId
when selecting the SSP route parameter, falling back to the provided sspId only
when the node has no SSP identifier. Preserve the existing unscoped risks:detail
route when neither value is available.

In `@src/views/evidence/__tests__/ViewView.spec.ts`:
- Around line 666-727: Extend the risks-tab tests around mountView and
clickButtonByText to set refs.risksError, assert the “Failed to load risks”
message, and verify loadEvidenceRisks is retried after switching away from and
back to the Risks tab following the failure. Ensure the test covers the failed
request without marking the current evidence UUID as successfully loaded.

In `@src/views/evidence/partial/EvidenceForm.vue`:
- Around line 305-329: Update the propsList and linksList initialization in the
evidence form to deep-clone each Property and Link element rather than only
copying the outer arrays. Ensure PropsEditor and LinksEditor mutate form-local
objects, leaving props.evidence and the fetched source data unchanged until
submission.

In `@src/views/evidence/ViewView.vue`:
- Around line 1305-1322: Update refreshEvidenceRisks so risksLoadedForUuid is
assigned the current streamUuid only after loadEvidenceRisks completes
successfully. Keep the existing UUID validation and ensureEvidenceRisksLoaded
retry behavior unchanged, allowing failed requests to be attempted again.

---

Outside diff comments:
In `@src/components/risk/RiskCreateForm.vue`:
- Around line 302-310: Update the register-risk creation flow in RiskCreateForm,
including the useDataApi response type and created emit payload, to use the
actual register-risk shape containing the id field rather than OSCAL Risk.
Propagate that type to consumers such as onRiskCreated so they access the typed
id directly and remove the unsafe cast.

In `@src/views/lineage/LineageGraphView.vue`:
- Around line 300-375: Extract the duplicated node-card markup into a shared
LineageNodeBox component accepting node, colIndex, and selectedKey props and
emitting boxClick and detailsClick events. Move the existing nodeCardClass,
selection-ring class, setBoxRef wiring, LineageNodeRow, child/leaf indicator,
and details button behavior into that component, then replace both the
structuralNodes(col) and risk group.nodes templates in LineageGraphView with it
while preserving their existing loops and event behavior.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 20d2b7f7-3653-4a59-813d-19abdba69e83

📥 Commits

Reviewing files that changed from the base of the PR and between f7cd10e and 23ecb21.

📒 Files selected for processing (17)
  • src/components/forms/LinksEditor.vue
  • src/components/forms/PropsEditor.vue
  • src/components/lineage/__tests__/nodeMeta.spec.ts
  • src/components/lineage/nodeMeta.ts
  • src/components/risk/RiskCreateForm.vue
  • src/composables/useLineage/fixtures.ts
  • src/composables/useLineage/types.ts
  • src/views/evidence/CreateView.vue
  • src/views/evidence/UpdateView.vue
  • src/views/evidence/ViewView.vue
  • src/views/evidence/__tests__/ViewView.spec.ts
  • src/views/evidence/partial/EvidenceForm.vue
  • src/views/lineage/LineageGraphView.vue
  • src/views/lineage/LineageTreeView.vue
  • src/views/lineage/__tests__/LineageGraphView.spec.ts
  • src/views/lineage/__tests__/ranking.spec.ts
  • src/views/lineage/ranking.ts

Comment thread src/components/forms/LinksEditor.vue
Comment thread src/components/lineage/nodeMeta.ts
Comment thread src/views/evidence/__tests__/ViewView.spec.ts
Comment thread src/views/evidence/partial/EvidenceForm.vue Outdated
Comment thread src/views/evidence/ViewView.vue

@gusfcarvalho gusfcarvalho left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(Would be REQUEST_CHANGES — GitHub blocks that on your own PR, so filing as COMMENT.) Findings inline. Nice PR overall — clean editor extraction, good defensive nodeMeta/ranking helpers, solid test coverage.

Medium: lineage nodeDetailRoute routes risk nodes through the active scope's SSP rather than the risk's own node.sspId (which this PR added and uses everywhere else), sending cross-SSP risks to the wrong/guessed SSP — your own ViewView test documents the correct behavior ("the risk's own SSP, not the active one").

Low: premature risksLoadedForUuid caching blocks retry after a failed risk load.

Out-of-scope note: re-submit drops existing backMatter attachments while keeping their #resource links, but that's pre-existing, not introduced here.

Comment thread src/components/lineage/nodeMeta.ts Outdated
Comment thread src/views/evidence/ViewView.vue Outdated
@gusfcarvalho
gusfcarvalho merged commit 27752d7 into main Jul 13, 2026
2 of 3 checks passed
@gusfcarvalho
gusfcarvalho deleted the gc-evidence-form-risks branch July 13, 2026 15:36

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/views/evidence/ViewView.vue (1)

1338-1348: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Add user feedback when riskId is missing in onRiskCreated.

The id?: string type explicitly accounts for the API not returning an id, but when riskId is undefined the function closes the dialog and returns silently — the risk was created but not linked, with no toast or indication to the user.

🛡️ Proposed fix: warn the user before returning
   if (!riskId || !sspId || !streamUuid) {
+    toast.add({
+      severity: 'warn',
+      summary: 'Risk not linked',
+      detail:
+        'The risk was created, but it could not be linked to this evidence.',
+      life: 5000,
+    });
     return;
   }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/views/evidence/ViewView.vue` around lines 1338 - 1348, The onRiskCreated
function currently returns silently when riskId is missing, leaving the created
risk unlinked without user feedback. Before the early return for a missing
riskId, show a warning toast or equivalent user notification explaining that the
risk was created but could not be linked; preserve the existing return behavior
for missing sspId or streamUuid.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@src/views/evidence/ViewView.vue`:
- Around line 1338-1348: The onRiskCreated function currently returns silently
when riskId is missing, leaving the created risk unlinked without user feedback.
Before the early return for a missing riskId, show a warning toast or equivalent
user notification explaining that the risk was created but could not be linked;
preserve the existing return behavior for missing sspId or streamUuid.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 0ec0e2e0-884b-4114-8f1c-a6a312555f91

📥 Commits

Reviewing files that changed from the base of the PR and between 23ecb21 and f520f71.

📒 Files selected for processing (8)
  • src/components/forms/LinksEditor.vue
  • src/components/forms/PropsEditor.vue
  • src/components/lineage/__tests__/nodeMeta.spec.ts
  • src/components/lineage/nodeMeta.ts
  • src/components/risk/RiskCreateForm.vue
  • src/views/evidence/ViewView.vue
  • src/views/evidence/__tests__/ViewView.spec.ts
  • src/views/evidence/partial/EvidenceForm.vue

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants