Skip to content

NO-JIRA: feat: display korrel8r markers in the graph#236

Open
alanconway wants to merge 1 commit into
openshift:mainfrom
alanconway:markers
Open

NO-JIRA: feat: display korrel8r markers in the graph#236
alanconway wants to merge 1 commit into
openshift:mainfrom
alanconway:markers

Conversation

@alanconway
Copy link
Copy Markdown
Contributor

@alanconway alanconway commented May 15, 2026

Korrel8r can add "markers" to nodes to indicate special conditions.

  • updated korrel8r/korrel8r-openapi.yaml, includes markers in graph nodes.
  • updated topology nodes to display markers in graph.
  • mark node matching current view "selected", follow view changes.

Summary by CodeRabbit

  • New Features

    • Added constraint parameter to the objects search endpoint
    • Nodes now display marker information with counts
    • Topology view supports URL-based node selection
  • Style

    • Refactored node visual states from error-based to disabled appearance with reduced opacity and grayscale effects
    • Added marker badge styling to topology nodes
  • Tests

    • Updated node constructor tests to reflect new markers field

Korrel8r can add "markers" to nodes to indicate special conditions.

- updated korrel8r/korrel8r-openapi.yaml, includes markers in graph nodes.
- updated topology nodes to display markers in graph.
- mark node matching current view "selected", follow view changes.
@openshift-ci-robot openshift-ci-robot added the jira/valid-reference Indicates that this PR references a valid Jira ticket of any type. label May 15, 2026
@openshift-ci-robot
Copy link
Copy Markdown

@alanconway: This pull request explicitly references no jira issue.

Details

In response to this:

Korrel8r can add "markers" to nodes to indicate special conditions.

  • updated korrel8r/korrel8r-openapi.yaml, includes markers in graph nodes.
  • updated topology nodes to display markers in graph.
  • mark node matching current view "selected", follow view changes.

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the openshift-eng/jira-lifecycle-plugin repository.

@openshift-ci openshift-ci Bot requested review from jgbernalp and shwetaap May 15, 2026 17:11
@openshift-ci
Copy link
Copy Markdown

openshift-ci Bot commented May 15, 2026

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: alanconway

The full list of commands accepted by this bot can be found here.

The pull request process is described here

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@openshift-ci openshift-ci Bot added the approved Indicates a PR has been approved by an approver from all required OWNERS files. label May 15, 2026
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 15, 2026

Walkthrough

This PR adds marker count visualization and disabled-node state to the topology graph. The OpenAPI schema defines a new MarkerCount type and adds a markers array to nodes; TypeScript types are updated to match. The topology component now renders disabled nodes with reduced visibility and displays marker badges; selection and context menus respect disabled state.

Changes

Marker support and disabled state

Layer / File(s) Summary
API schema and type contracts
korrel8r/korrel8r-openapi.yaml, web/src/korrel8r/types.ts, web/src/korrel8r/client/index.ts, web/src/__tests__/types.spec.ts
OpenAPI document version is set to 0.10.1-dev; GET /objects adds constraint parameter; Node schema includes markers array referencing new MarkerCount; TypeScript Node class replaces error: Error with disabled: string, adds markers array and hasMarkers getter; MarkerCount type is exported; test expects markers field.
Component imports and status helpers
web/src/components/topology/Korrel8rTopology.tsx
Badge and NodeStatus are imported; useLocationQuery hook added for URL-based selection; nodeStatusProps helper computes status decorator configuration from node.disabled and node.hasMarkers.
Node rendering with disabled styling and badges
web/src/components/topology/Korrel8rTopology.tsx, web/src/components/topology/korrel8rtopology.css
DefaultNode now applies disabled class, label, badge count, and status decorator; CSS rules for .tp-plugin__topology_node--disabled (opacity, grayscale) and .tp-plugin__topology_marker_badge styling are added; invalid-node logic switches from node.error to node.disabled.
Selection and context menu logic
web/src/components/topology/Korrel8rTopology.tsx
useEffect initializes selectedIds from URL query; node.disabled is set for missing console links or disabled plugin domains; selectionAction checks node exists and is not disabled; nodeMenu and context menu items respect disabled state; Badge component displays query count in menu items.
Graph node lookup safety
web/src/korrel8r/types.ts
Graph.node() accesses nodeByClass via optional chaining instead of direct bracket access.

🎯 3 (Moderate) | ⏱️ ~25 minutes

🚥 Pre-merge checks | ✅ 12
✅ Passed checks (12 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately and specifically describes the main feature addition: displaying korrel8r markers in the graph topology visualization.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
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.
Stable And Deterministic Test Names ✅ Passed PR does not modify any Ginkgo tests. Repository uses Jest (TypeScript) and Go standard testing package. Custom check for Ginkgo test names is not applicable.
Test Structure And Quality ✅ Passed Custom check for Ginkgo test structure is not applicable. The repository uses Jest for TypeScript tests and Go testing package for Go tests, with no Ginkgo tests found anywhere in the codebase.
Microshift Test Compatibility ✅ Passed No new Ginkgo e2e tests were added. PR contains OpenAPI schema, React components, Jest tests, and CSS changes only. Custom check not applicable.
Single Node Openshift (Sno) Test Compatibility ✅ Passed No Ginkgo e2e tests were added in this PR. New test files are standard Go unit tests using testing.T, not Ginkgo. Check is not applicable.
Topology-Aware Scheduling Compatibility ✅ Passed Check not applicable. PR modifies only frontend code (React components, CSS, TypeScript types, OpenAPI schema) with no deployment manifests, operator code, or controllers being modified.
Ote Binary Stdout Contract ✅ Passed Go binary code added has no stdout writes (fmt.Print*, klog, os.Stdout). No init() functions or package-level prints. All logging via logrus which outputs to stderr by default.
Ipv6 And Disconnected Network Test Compatibility ✅ Passed No Ginkgo e2e tests are added in this PR. The PR modifies OpenAPI specs, TypeScript code, CSS, and includes a Jest/Vitest unit test—not Ginkgo e2e tests. The custom check is not applicable.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Tip

💬 Introducing Slack Agent: The best way for teams to turn conversations into code.

Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.

  • Generate code and open pull requests
  • Plan features and break down work
  • Investigate incidents and troubleshoot customer tickets together
  • Automate recurring tasks and respond to alerts with triggers
  • Summarize progress and report instantly

Built for teams:

  • Shared memory across your entire org—no repeating context
  • Per-thread sandboxes to safely plan and execute work
  • Governance built-in—scoped access, auditability, and budget controls

One agent for your entire SDLC. Right inside Slack.

👉 Get started


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

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 4

Caution

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

⚠️ Outside diff range comments (2)
web/src/components/topology/Korrel8rTopology.tsx (1)

204-208: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Guard context-menu title against missing node.class.

At Line 206/207, node.class.toString() can throw for parse-failed nodes (where Node.class is unset and disabled is set).

Suggested fix
-      const menu = [
-        <ContextMenuItem isDisabled={true} key={node.class.toString()}>
-          <Title headingLevel="h4">{node.class.toString()}</Title>
+      const title = node.class?.toString?.() ?? node.id;
+      const menu = [
+        <ContextMenuItem isDisabled={true} key={title}>
+          <Title headingLevel="h4">{title}</Title>
         </ContextMenuItem>,
       ];
🤖 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 `@web/src/components/topology/Korrel8rTopology.tsx` around lines 204 - 208, The
context menu title uses node.class.toString() which can throw when node.class is
undefined for parse-failed nodes; update the block that builds the menu (the
code that reads const node: korrel8r.Node = e.getData() and constructs the
ContextMenuItem/Title) to safely access node.class (e.g., check node.class !==
undefined/null or use a fallback variable like const classLabel = node.class ?
node.class.toString() : "Unknown" or an empty string) and pass that safe string
into Title so no exception occurs for missing classes.
web/src/__tests__/types.spec.ts (1)

154-160: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Update bad-class test to the new disabled field contract.

At Line 158, the expected shape still uses error, but Node now records parse failures in disabled.

Suggested fix
   it('constructor bad class', () => {
     expect(new Node({ class: 'foobar', count: 1 })).toEqual({
       id: 'foobar',
       count: 1,
-      error: new TypeError('invalid class: foobar'),
+      disabled: 'invalid class: foobar',
       queries: [],
+      markers: [],
     });
   });
🤖 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 `@web/src/__tests__/types.spec.ts` around lines 154 - 160, The test
"constructor bad class" expects the old `error` field; update it to the new
`disabled` contract by replacing the `error` property with `disabled` containing
the parse failure (e.g. new TypeError('invalid class: foobar')), so the expected
object returned by new Node({ class: 'foobar', count: 1 }) should include id
'foobar', count 1, disabled: new TypeError('invalid class: foobar'), and
queries: [] — update the assertion in the test to reference `disabled` instead
of `error`.
🤖 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 `@web/src/components/topology/Korrel8rTopology.tsx`:
- Around line 153-164: The current mapping in nodes (useMemo) mutates the source
graph.nodes by setting node.disabled directly, which can persist incorrect
state; instead, do not modify graph.nodes in-place—create and return new
NodeModel objects (or shallow copies of each korrel8r.Node) and set the disabled
display string on those copies based on loggingAvailable, netobserveAvailable
and the existing node.disabled value (using korrel8r.Node, graph.nodes,
node.disabled, loggingAvailable, netobserveAvailable and t()) so the UI state is
derived immutably and availability changes won’t leak into the original graph
data.
- Line 125: In Korrel8rTopology.tsx inside the JSX that renders the title and
topologyNode (the line containing
<title>{node.disabled}</title>){topologyNode}), remove the stray closing
parenthesis so the fragment flows directly from the closing </title> to
{topologyNode}; locate the JSX in the Korrel8rTopology component where
node.disabled and topologyNode are used and change that sequence to end the
</title> tag and then immediately render {topologyNode}.

In `@web/src/korrel8r/types.ts`:
- Around line 273-274: Node constructor assigns this.markers directly from
node.markers which may be undefined; update the Node constructor to default
markers to an empty array (e.g., set this.markers = node.markers ?? [] or use a
fallback) so this.markers is always an array and preserves the expected shape
for consumers (refer to the Node constructor and the this.markers / node.markers
symbols).
- Line 353: The getter is accessing a Map using bracket notation
(this.nodeByClass?.[id]) which bypasses the Map API and types; replace that
access with the Map#get method (this.nodeByClass?.get(id)) and ensure the
declared return type reflects Node | undefined if it currently asserts Node;
update any corresponding set usage to Map#set if needed so nodeByClass is
consistently accessed via .get/.set (refer to the nodeByClass property and the
function/method containing the return).

---

Outside diff comments:
In `@web/src/__tests__/types.spec.ts`:
- Around line 154-160: The test "constructor bad class" expects the old `error`
field; update it to the new `disabled` contract by replacing the `error`
property with `disabled` containing the parse failure (e.g. new
TypeError('invalid class: foobar')), so the expected object returned by new
Node({ class: 'foobar', count: 1 }) should include id 'foobar', count 1,
disabled: new TypeError('invalid class: foobar'), and queries: [] — update the
assertion in the test to reference `disabled` instead of `error`.

In `@web/src/components/topology/Korrel8rTopology.tsx`:
- Around line 204-208: The context menu title uses node.class.toString() which
can throw when node.class is undefined for parse-failed nodes; update the block
that builds the menu (the code that reads const node: korrel8r.Node =
e.getData() and constructs the ContextMenuItem/Title) to safely access
node.class (e.g., check node.class !== undefined/null or use a fallback variable
like const classLabel = node.class ? node.class.toString() : "Unknown" or an
empty string) and pass that safe string into Title so no exception occurs for
missing classes.
🪄 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: Repository YAML (base), Central YAML (inherited)

Review profile: CHILL

Plan: Enterprise

Run ID: 0ba6c6b1-487d-46c8-8caf-2dd08a8a5b5b

📥 Commits

Reviewing files that changed from the base of the PR and between 8a8dbcf and 69cda67.

⛔ Files ignored due to path filters (1)
  • web/src/korrel8r/client/types.gen.ts is excluded by !**/*.gen.*
📒 Files selected for processing (6)
  • korrel8r/korrel8r-openapi.yaml
  • web/src/__tests__/types.spec.ts
  • web/src/components/topology/Korrel8rTopology.tsx
  • web/src/components/topology/korrel8rtopology.css
  • web/src/korrel8r/client/index.ts
  • web/src/korrel8r/types.ts

return (
<g opacity="0.7" className="tp-plugin__topology_invalid_node">
<title>{node.error}</title>){topologyNode}
<title>{node.disabled}</title>){topologyNode}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail
# Detect the exact malformed JSX token sequence.
rg -n "title>\\{node\\.disabled\\}</title>\\)\\{topologyNode\\}" web/src/components/topology/Korrel8rTopology.tsx

Repository: openshift/troubleshooting-panel-console-plugin

Length of output: 148


🏁 Script executed:

# View context around line 125 to understand the structure
cat -n web/src/components/topology/Korrel8rTopology.tsx | sed -n '115,135p'

Repository: openshift/troubleshooting-panel-console-plugin

Length of output: 765


🏁 Script executed:

# Search for graph.nodes mutations to verify state mutation concern
rg -n "graph\.nodes\s*=" web/src/components/topology/Korrel8rTopology.tsx

Repository: openshift/troubleshooting-panel-console-plugin

Length of output: 72


🏁 Script executed:

# Check node.class usage patterns
rg -n "node\.class" web/src/components/topology/Korrel8rTopology.tsx -A 2 -B 2

Repository: openshift/troubleshooting-panel-console-plugin

Length of output: 1027


Remove stray ) causing JSX parse failure.

At line 125, the closing </title> tag is followed by an extra ) that will cause a syntax error. The element should be followed directly by {topologyNode} on the next line.

Suggested fix
-        <title>{node.disabled}</title>){topologyNode}
+        <title>{node.disabled}</title>
+        {topologyNode}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<title>{node.disabled}</title>){topologyNode}
<title>{node.disabled}</title>
{topologyNode}
🤖 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 `@web/src/components/topology/Korrel8rTopology.tsx` at line 125, In
Korrel8rTopology.tsx inside the JSX that renders the title and topologyNode (the
line containing <title>{node.disabled}</title>){topologyNode}), remove the stray
closing parenthesis so the fragment flows directly from the closing </title> to
{topologyNode}; locate the JSX in the Korrel8rTopology component where
node.disabled and topologyNode are used and change that sequence to end the
</title> tag and then immediately render {topologyNode}.

Comment on lines +153 to 164
const nodes: NodeModel[] = useMemo(
(): NodeModel[] =>
graph.nodes.map((node: korrel8r.Node) => {
const newNode = { ...node };
if (newNode.error) {
if (node.disabled) {
// eslint-disable-next-line no-console
console.warn(`korrel8r node: ${newNode.error}`);
newNode.error = Error(t('Unable to find Console Link'));
} else if (newNode.class.domain === 'log' && !loggingAvailable) {
newNode.error = Error(t('Logging Plugin Disabled'));
} else if (newNode.class.domain === 'netflow' && !netobserveAvailable) {
newNode.error = Error(t('Netflow Plugin Disabled'));
console.warn(`korrel8r node: ${node.disabled}`);
node.disabled = t('Unable to find Console Link');
} else if (node.class.domain === 'log' && !loggingAvailable) {
node.disabled = t('Logging Plugin Disabled');
} else if (node.class.domain === 'netflow' && !netobserveAvailable) {
node.disabled = t('Netflow Plugin Disabled');
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Avoid mutating graph.nodes when deriving disabled UI state.

At Lines 156-163, mutating node.disabled in-place can leave nodes permanently disabled/wrongly labeled across later renders when availability flags change.

Suggested fix
-      graph.nodes.map((node: korrel8r.Node) => {
-        if (node.disabled) {
+      graph.nodes.map((node: korrel8r.Node) => {
+        const disabled =
+          node.disabled
+            ? t('Unable to find Console Link')
+            : node.class.domain === 'log' && !loggingAvailable
+              ? t('Logging Plugin Disabled')
+              : node.class.domain === 'netflow' && !netobserveAvailable
+                ? t('Netflow Plugin Disabled')
+                : undefined;
+        if (node.disabled) {
           // eslint-disable-next-line no-console
           console.warn(`korrel8r node: ${node.disabled}`);
-          node.disabled = t('Unable to find Console Link');
-        } else if (node.class.domain === 'log' && !loggingAvailable) {
-          node.disabled = t('Logging Plugin Disabled');
-        } else if (node.class.domain === 'netflow' && !netobserveAvailable) {
-          node.disabled = t('Netflow Plugin Disabled');
         }
         return {
           id: node.id,
@@
-          data: node,
+          data: { ...node, disabled },
         };
       }),
🤖 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 `@web/src/components/topology/Korrel8rTopology.tsx` around lines 153 - 164, The
current mapping in nodes (useMemo) mutates the source graph.nodes by setting
node.disabled directly, which can persist incorrect state; instead, do not
modify graph.nodes in-place—create and return new NodeModel objects (or shallow
copies of each korrel8r.Node) and set the disabled display string on those
copies based on loggingAvailable, netobserveAvailable and the existing
node.disabled value (using korrel8r.Node, graph.nodes, node.disabled,
loggingAvailable, netobserveAvailable and t()) so the UI state is derived
immutably and availability changes won’t leak into the original graph data.

Comment thread web/src/korrel8r/types.ts
Comment on lines +273 to +274
this.markers = node.markers;
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Default markers to an empty array in Node constructor.

At Line 273, node.markers is optional in the API contract; assigning it directly can leave this.markers undefined and break shape expectations.

Suggested fix
-    this.markers = node.markers;
+    this.markers = node.markers ?? [];
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
this.markers = node.markers;
}
this.markers = node.markers ?? [];
}
🤖 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 `@web/src/korrel8r/types.ts` around lines 273 - 274, Node constructor assigns
this.markers directly from node.markers which may be undefined; update the Node
constructor to default markers to an empty array (e.g., set this.markers =
node.markers ?? [] or use a fallback) so this.markers is always an array and
preserves the expected shape for consumers (refer to the Node constructor and
the this.markers / node.markers symbols).

Comment thread web/src/korrel8r/types.ts

node(id: string): Node {
return this.nodeByClass[id];
return this.nodeByClass?.[id];
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail
# Verify Map declaration and non-Map-style indexing usage.
rg -n "nodeByClass|new Map\\(|\\.set\\(|\\.get\\(|\\[id\\]|\\[n\\.class\\]" web/src/korrel8r/types.ts -C2

Repository: openshift/troubleshooting-panel-console-plugin

Length of output: 1406


Use Map#get() and Map#set() consistently for nodeByClass access instead of bracket notation.

At line 353, bracket indexing ?.[id] is used on a Map, which is not the Map API and bypasses type safety. The return type annotation claims Node but bracket notation actually returns Node | undefined. Use .get(id) instead, which properly returns Node | undefined.

Suggested fix
 export class Graph {
   nodes: Array<Node>;
   edges: Array<Edge>;

   private nodeByClass: Map<string, Node>;

   constructor(graph: api.Graph) {
     this.nodeByClass = new Map();
     this.nodes = (graph?.nodes ?? []).map((n) => {
       const node = new Node(n);
-      this.nodeByClass[n.class] = node;
+      this.nodeByClass.set(n.class, node);
       return node;
     });
@@
-  node(id: string): Node {
-    return this.nodeByClass?.[id];
+  node(id: string): Node | undefined {
+    return this.nodeByClass.get(id);
   }
 }
🤖 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 `@web/src/korrel8r/types.ts` at line 353, The getter is accessing a Map using
bracket notation (this.nodeByClass?.[id]) which bypasses the Map API and types;
replace that access with the Map#get method (this.nodeByClass?.get(id)) and
ensure the declared return type reflects Node | undefined if it currently
asserts Node; update any corresponding set usage to Map#set if needed so
nodeByClass is consistently accessed via .get/.set (refer to the nodeByClass
property and the function/method containing the return).

@openshift-ci
Copy link
Copy Markdown

openshift-ci Bot commented May 15, 2026

@alanconway: The following test failed, say /retest to rerun all failed tests or /retest-required to rerun all mandatory failed tests:

Test name Commit Details Required Rerun command
ci/prow/unit 69cda67 link true /test unit

Full PR test history. Your PR dashboard.

Details

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository. I understand the commands that are listed here.

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

Labels

approved Indicates a PR has been approved by an approver from all required OWNERS files. jira/valid-reference Indicates that this PR references a valid Jira ticket of any type.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants