Skip to content

Conversation

@nikhilsaikethe
Copy link
Contributor

@nikhilsaikethe nikhilsaikethe commented Sep 23, 2025

User description

This PR solves the issue of deleting the default destination node added implicitly so it will throw a warning message and also it will be only available for realtime pipeline because we only add default destination node for realtime pipelines #8597 8597


PR Type

Bug fix, Enhancement


Description

  • Warn on deleting default destination node

  • Detect default output for realtime pipelines

  • Add reusable warning message constant

  • Extend confirm dialog to show banner


Diagram Walkthrough

flowchart LR
  useDnD["useDnD: detect default destination"] -- "expose checkIfDefaultDestinationNode" --> StreamVue["Stream.vue: delete dialog"]
  useDnD -- "expose checkIfDefaultDestinationNode" --> CustomNodeVue["CustomNode.vue: delete dialog"]
  constants["constants.ts: warning message"] -- "import" --> StreamVue
  constants -- "import" --> CustomNodeVue
  ConfirmDialog["ConfirmDialog.vue: banner + width"] -- "render warningMessage" --> UI["User sees warning on delete"]
Loading

File Walkthrough

Relevant files
Enhancement
useDnD.ts
Add utilities to detect default destination node                 

web/src/plugins/pipelines/useDnD.ts

  • Add helper to get input stream name.
  • Add checker for default destination node by id.
  • Comment clarifying default node auto-addition.
  • Export checkIfDefaultDestinationNode.
+24/-1   
ConfirmDialog.vue
Enhance dialog to display warning banner                                 

web/src/components/ConfirmDialog.vue

  • Support optional warningMessage prop.
  • Render themed banner when warning present.
  • Adjust dialog width conditionally.
  • Inject Vuex store for theming.
+30/-2   
Documentation
constants.ts
Centralize default destination warning message                     

web/src/utils/pipelines/constants.ts

  • Add defaultDestinationNodeWarningMessage constant.
+1/-0     
Bug fix
Stream.vue
Show warning when deleting default destination (form)       

web/src/components/pipeline/NodeForm/Stream.vue

  • Pass warningMessage to ConfirmDialog.
  • Import and use warning message constant.
  • Use checkIfDefaultDestinationNode before delete.
  • Clear warning for non-default nodes/cancel dialog.
+12/-1   
CustomNode.vue
Warn on deleting default destination (node card)                 

web/src/plugins/pipelines/CustomNode.vue

  • Import warning constant and checker.
  • Populate warning when deleting default destination.
  • Pass warningMessage to ConfirmDialog.
+11/-1   

@github-actions
Copy link
Contributor

PR Reviewer Guide 🔍

Here are some key observations to aid the review process:

⏱️ Estimated effort to review: 2 🔵🔵⚪⚪⚪
🧪 No relevant tests
🔒 No security concerns identified
⚡ Recommended focus areas for review

Possible Issue

The helper checkIfDefaultDestinationNode may return undefined when no input stream exists, which is then used in conditions expecting a boolean. Consider returning an explicit boolean to avoid truthiness pitfalls and improve readability.

const checkIfDefaultDestinationNode = (id: string) => {
  const inputNodeStream = getInputNodeStream();
  const nodes = pipelineObj.currentSelectedPipeline?.nodes ?? [];
  if(inputNodeStream){
    return nodes.some((node: any) => node.id === id && node.type === 'output' && (node.data.stream_name.value === inputNodeStream || node.data.stream_name === inputNodeStream));
  }
};
Robustness

Accessing node.data.stream_name.value assumes data and stream_name shapes; missing or differently shaped values could throw. Add optional chaining or guards to prevent runtime errors on heterogeneous node data.

const checkIfDefaultDestinationNode = (id: string) => {
  const inputNodeStream = getInputNodeStream();
  const nodes = pipelineObj.currentSelectedPipeline?.nodes ?? [];
  if(inputNodeStream){
    return nodes.some((node: any) => node.id === id && node.type === 'output' && (node.data.stream_name.value === inputNodeStream || node.data.stream_name === inputNodeStream));
  }
};
Styling Coupling

The dialog width and banner styling are conditional on warningMessage and theme via Vuex store. Verify SSR/initial render doesn’t flash incorrect size and ensure store availability; consider default width classes and null-safe access.

<q-card
  data-test="dialog-box"
  :class="warningMessage && warningMessage.length > 0 ? 'tw-w-[500px]' : 'tw-w-[240px]'"
>
  <q-card-section class="confirmBody">
    <div class="head">{{ title }}</div>
    <div class="para">{{ message }}</div>
    <div v-if="warningMessage && warningMessage.length > 0" class="tw-mt-4">
      <q-banner :class="[
        'tw-border-l-4 tw-p-4 tw-rounded',
        store.state.theme === 'dark' 
          ? 'tw-bg-gray-800/60 tw-border-yellow-600/70' 
          : 'tw-bg-orange-50 tw-border-orange-400'
      ]">
        <template v-slot:avatar>
          <q-icon 
            name="warning" 
            :class="store.state.theme === 'dark' ? 'tw-text-yellow-500/80' : 'tw-text-orange-500'" 
            size="24px" 
          />
        </template>
        <div :class="[
          'tw-font-medium tw-text-sm tw-leading-relaxed',
          store.state.theme === 'dark' ? 'tw-text-gray-300' : 'tw-text-orange-800'
        ]">
          {{ warningMessage }}
        </div>
      </q-banner>
    </div>

@github-actions
Copy link
Contributor

github-actions bot commented Sep 23, 2025

PR Code Suggestions ✨

Latest suggestions up to 4a9bfaa
Explore these optional code suggestions:

CategorySuggestion                                                                                                                                    Impact
Possible issue
Always return strict boolean

Ensure this function always returns a boolean. Currently, if inputNodeStream is
truthy but no node matches, the function returns undefined. Also, guard against
optional properties to prevent runtime errors when node.data or stream_name is
missing.

web/src/plugins/pipelines/useDnD.ts [595-602]

-const checkIfDefaultDestinationNode = (id: string) => {
+const checkIfDefaultDestinationNode = (id: string): boolean => {
   const inputNodeStream = getInputNodeStream();
   if (!inputNodeStream) return false;
   const nodes = pipelineObj.currentSelectedPipeline?.nodes ?? [];
-  if(inputNodeStream){
-    return nodes.some((node: any) => node.id === id && node.type === 'output' && (node.data.stream_name.value === inputNodeStream || node.data.stream_name === inputNodeStream));
-  }
+  return nodes.some(
+    (node: any) =>
+      node?.id === id &&
+      node?.type === 'output' &&
+      (
+        node?.data?.stream_name?.value === inputNodeStream ||
+        node?.data?.stream_name === inputNodeStream
+      )
+  );
 };
Suggestion importance[1-10]: 7

__

Why: Correctly identifies that the function may return undefined and adds optional chaining to prevent runtime errors; this is accurate and improves robustness but is not a critical bug fix.

Medium
Guard against missing fields

Add safe optional access to avoid runtime crashes if currentSelectedNodeData, data,
or position are missing during drag events. Failing to guard can break the DnD flow
under unexpected states.

web/src/plugins/pipelines/useDnD.ts [476-480]

-if(pipelineObj.currentSelectedNodeData.type == 'input' && pipelineObj.currentSelectedNodeData.data.node_type == 'stream' && pipelineObj.currentSelectedPipeline.nodes.length === 1){
-  const position = {x:pipelineObj.currentSelectedNodeData.position.x, y:pipelineObj.currentSelectedNodeData.position.y+200};
+if (
+  pipelineObj?.currentSelectedNodeData?.type === 'input' &&
+  pipelineObj?.currentSelectedNodeData?.data?.node_type === 'stream' &&
+  pipelineObj?.currentSelectedPipeline?.nodes?.length === 1
+) {
+  const basePos = pipelineObj.currentSelectedNodeData.position ?? { x: 0, y: 0 };
+  const position = { x: basePos.x, y: basePos.y + 200 };
 
   const nodeId = getUUID();
Suggestion importance[1-10]: 7

__

Why: Adding null-safe checks and defaults around currentSelectedNodeData and position reduces risk of crashes during DnD; sound improvement but not addressing a confirmed crash path.

Medium
Prevent undefined length access

Avoid accessing warningMessage.length when it may be null or undefined. Use optional
chaining or a truthy check to prevent runtime errors when the prop is omitted.

web/src/components/ConfirmDialog.vue [19-22]

 <q-card
   data-test="dialog-box"
-  :class="warningMessage && warningMessage.length > 0 ? 'tw-w-[500px]' : 'tw-w-[240px]'"
+  :class="warningMessage?.length ? 'tw-w-[500px]' : 'tw-w-[240px]'"
 >
Suggestion importance[1-10]: 6

__

Why: Using optional chaining on warningMessage?.length prevents potential runtime errors when the prop is absent; moderate impact and accurate in context.

Low

Previous suggestions

Suggestions up to commit aae43a3
CategorySuggestion                                                                                                                                    Impact
Possible issue
Guarantee safe boolean return

Ensure the function always returns a boolean and avoid accessing nested properties
without guards to prevent crashes. Return false when inputNodeStream is null and
safely access node.data?.stream_name?.value.

web/src/plugins/pipelines/useDnD.ts [595-601]

-const checkIfDefaultDestinationNode = (id: string) => {
+const checkIfDefaultDestinationNode = (id: string): boolean => {
   const inputNodeStream = getInputNodeStream();
+  if (!inputNodeStream) return false;
   const nodes = pipelineObj.currentSelectedPipeline?.nodes ?? [];
-  if(inputNodeStream){
-    return nodes.some((node: any) => node.id === id && node.type === 'output' && (node.data.stream_name.value === inputNodeStream || node.data.stream_name === inputNodeStream));
-  }
+  return nodes.some((node: any) => {
+    if (node?.id !== id || node?.type !== "output") return false;
+    const stream = node?.data?.stream_name?.value ?? node?.data?.stream_name ?? null;
+    return stream === inputNodeStream;
+  });
 };
Suggestion importance[1-10]: 8

__

Why: Ensuring a consistent boolean return and guarding nested access prevents potential crashes when properties are missing. This directly strengthens the new utility’s correctness with minimal risk.

Medium
Add robust null checks

Guard against cases where inputNode or inputNode.data are undefined to prevent
runtime errors when no input node exists. Also normalize return to consistently be a
string or null, avoiding empty-string ambiguities.

web/src/plugins/pipelines/useDnD.ts [584-593]

-const getInputNodeStream = () => {
+const getInputNodeStream = (): string | null => {
   const nodes = pipelineObj.currentSelectedPipeline?.nodes ?? [];
-  const inputNode = nodes.find((node: any) => node.io_type === "input");
-  if(inputNode.data.hasOwnProperty('node_type') &&  inputNode.data.node_type === 'stream'){
-    return inputNode?.data?.stream_name?.value || inputNode.data.stream_name || "";
+  const inputNode = nodes.find((node: any) => node?.io_type === "input");
+  if (!inputNode || !inputNode.data) return null;
+  if (Object.prototype.hasOwnProperty.call(inputNode.data, "node_type") && inputNode.data.node_type === "stream") {
+    const stream = inputNode.data?.stream_name?.value ?? inputNode.data?.stream_name ?? null;
+    return typeof stream === "string" && stream.length > 0 ? stream : null;
   }
-  else {
-    return null;
-  }
+  return null;
 };
Suggestion importance[1-10]: 7

__

Why: The change correctly guards inputNode and inputNode.data and normalizes the return to string | null, preventing runtime errors and ambiguous empty strings. It aligns with the new hunk code and improves safety without altering behavior.

Medium
General
Safely handle optional prop

Provide a default width when warningMessage is undefined to avoid truthy checks on
non-strings and ensure consistent sizing. Coerce to string length safely using
optional chaining.

web/src/components/ConfirmDialog.vue [19-22]

 <q-card
   data-test="dialog-box"
-  :class="warningMessage && warningMessage.length > 0 ? 'tw-w-[500px]' : 'tw-w-[240px]'"
+  :class="(warningMessage?.length ?? 0) > 0 ? 'tw-w-[500px]' : 'tw-w-[240px]'"
 >
Suggestion importance[1-10]: 6

__

Why: The optional chaining makes the class binding robust when warningMessage is undefined, though the current code already partially checks truthiness. It’s a small but valid defensive improvement.

Low

@nikhilsaikethe nikhilsaikethe force-pushed the pipeline-destination-node-warning branch from aae43a3 to a9bc479 Compare September 23, 2025 10:50
Copy link
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

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

Greptile Overview

Summary

This PR adds warning messages when users attempt to delete default destination nodes in realtime pipelines. The implementation spans four files:

  • Enhanced ConfirmDialog component to support warning messages with theme-appropriate styling using Tailwind classes
  • Added detection logic in useDnD.ts to identify default destination nodes by comparing stream names between input and output nodes
  • Integrated warning display in both Stream.vue and CustomNode.vue components to show the warning when deleting default destination nodes

Key changes:

  • Warning appears only for realtime pipelines where a default destination node was automatically added
  • Uses conditional logic to show appropriate warning message explaining data flow impact
  • Maintains consistent UI styling across light and dark themes

Confidence Score: 4/5

  • This PR is generally safe to merge with minor improvements needed
  • The implementation is solid but has one potential runtime error and minor style issues that should be addressed
  • Focus on web/src/plugins/pipelines/useDnD.ts for the null check fix

Important Files Changed

File Analysis

Filename        Score        Overview
web/src/components/ConfirmDialog.vue 5/5 Enhanced dialog component to support warning messages with theme-appropriate styling
web/src/components/pipeline/NodeForm/Stream.vue 4/5 Added warning message support for default destination node deletion with conditional logic
web/src/plugins/pipelines/CustomNode.vue 4/5 Integrated warning message for default destination node deletion in node context menu
web/src/plugins/pipelines/useDnD.ts 3/5 Core logic for identifying default destination nodes with stream name comparison

Sequence Diagram

sequenceDiagram
    participant User
    participant StreamNode as Stream/CustomNode
    participant DnDComposable as useDnD.ts
    participant ConfirmDialog as ConfirmDialog.vue
    
    User->>StreamNode: Click delete on node
    StreamNode->>DnDComposable: checkIfDefaultDestinationNode(nodeId)
    DnDComposable->>DnDComposable: getInputNodeStream()
    DnDComposable-->>StreamNode: Returns true if default destination
    
    alt Is Default Destination Node
        StreamNode->>StreamNode: Set warningMessage
        Note over StreamNode: "If you delete this default destination node..."
    else Not Default Destination
        StreamNode->>StreamNode: Clear warningMessage
    end
    
    StreamNode->>ConfirmDialog: Show dialog with warning
    ConfirmDialog->>User: Display confirmation with warning banner
    
    User->>ConfirmDialog: Click OK/Cancel
    alt User confirms
        ConfirmDialog->>StreamNode: Emit confirm
        StreamNode->>DnDComposable: deletePipelineNode(nodeId)
    else User cancels
        ConfirmDialog->>StreamNode: Emit cancel
        StreamNode->>StreamNode: Close dialog
    end
Loading

4 files reviewed, 3 comments

Edit Code Review Bot Settings | Greptile

Comment on lines 595 to 603
const checkIfDefaultDestinationNode = (id: string) => {
const inputNodeStream = getInputNodeStream();
const nodes = pipelineObj.currentSelectedPipeline?.nodes ?? [];
if(inputNodeStream){
return nodes.some((node: any) => node.id === id && node.type === 'output' && (node.data.stream_name.value === inputNodeStream || node.data.stream_name === inputNodeStream));
}
};

Copy link
Contributor

Choose a reason for hiding this comment

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

logic: potential runtime error if inputNode is undefined

Suggested change
const checkIfDefaultDestinationNode = (id: string) => {
const inputNodeStream = getInputNodeStream();
const nodes = pipelineObj.currentSelectedPipeline?.nodes ?? [];
if(inputNodeStream){
return nodes.some((node: any) => node.id === id && node.type === 'output' && (node.data.stream_name.value === inputNodeStream || node.data.stream_name === inputNodeStream));
}
};
const getInputNodeStream = () => {
const nodes = pipelineObj.currentSelectedPipeline?.nodes ?? [];
const inputNode = nodes.find((node: any) => node.io_type === "input");
if(!inputNode) return null;
if(inputNode.data.hasOwnProperty('node_type') && inputNode.data.node_type === 'stream'){
return inputNode?.data?.stream_name?.value || inputNode.data.stream_name || "";
}
else {
return null;
}
};

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes fixed that

Comment on lines 406 to 407
// //here we will check if the destination node is added by default if yes then we will show a warning message to the user
if(pipelineObj.currentSelectedNodeData?.data.hasOwnProperty('node_type') && pipelineObj.currentSelectedNodeData?.data.node_type === 'stream' && checkIfDefaultDestinationNode(pipelineObj.currentSelectedNodeID)){
Copy link
Contributor

Choose a reason for hiding this comment

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

style: inconsistent comment formatting - remove extra slash

Suggested change
// //here we will check if the destination node is added by default if yes then we will show a warning message to the user
if(pipelineObj.currentSelectedNodeData?.data.hasOwnProperty('node_type') && pipelineObj.currentSelectedNodeData?.data.node_type === 'stream' && checkIfDefaultDestinationNode(pipelineObj.currentSelectedNodeID)){
// here we will check if the destination node is added by default if yes then we will show a warning message to the user

Copy link
Contributor Author

Choose a reason for hiding this comment

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

sure

Comment on lines +172 to +174
//here we will check if the destination node is added by default if yes then we will show a warning message to the user
if(props.data?.hasOwnProperty('node_type') && props.data.node_type === 'stream' && checkIfDefaultDestinationNode(id)){
Copy link
Contributor

Choose a reason for hiding this comment

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

style: inconsistent comment formatting - remove extra slash

Suggested change
//here we will check if the destination node is added by default if yes then we will show a warning message to the user
if(props.data?.hasOwnProperty('node_type') && props.data.node_type === 'stream' && checkIfDefaultDestinationNode(id)){
// here we will check if the destination node is added by default if yes then we will show a warning message to the user

Copy link
Contributor Author

Choose a reason for hiding this comment

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

sure

@nikhilsaikethe nikhilsaikethe force-pushed the pipeline-destination-node-warning branch 3 times, most recently from 385c176 to 00fb99d Compare September 29, 2025 06:16
@nikhilsaikethe nikhilsaikethe marked this pull request as draft September 29, 2025 06:16
@nikhilsaikethe nikhilsaikethe self-assigned this Sep 29, 2025
@nikhilsaikethe nikhilsaikethe marked this pull request as ready for review September 29, 2025 15:35
@nikhilsaikethe nikhilsaikethe force-pushed the pipeline-destination-node-warning branch from 3a0f62a to 4a9bfaa Compare September 29, 2025 15:35
Copy link
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

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

Greptile Overview

Summary

This PR adds warning messages when users attempt to delete default destination nodes in realtime pipelines. The implementation correctly identifies default destination nodes by comparing the destination stream name with the input stream name and displays contextual warnings through an enhanced confirm dialog.

Key Changes:

  • Enhanced ConfirmDialog: Added optional warningMessage prop with themed warning banner and responsive width
  • Default Detection Logic: New checkIfDefaultDestinationNode() helper in useDnD.ts to identify auto-created destination nodes
  • Warning Integration: Both Stream.vue and CustomNode.vue now show warnings when deleting default destinations
  • Constants Extraction: Warning message moved to dedicated constants file for reusability

Issues Found:

  • Minor potential null access issue in getInputNodeStream() function that should be addressed

The implementation follows good separation of concerns with the detection logic centralized in useDnD.ts and shared constants. The UI properly handles both light and dark themes for the warning display.

Confidence Score: 4/5

  • This PR is safe to merge with minimal risk after addressing the null access issue
  • Score reflects well-structured implementation with good separation of concerns, proper theme handling, and effective warning system. One minor logical issue with potential null access reduces confidence slightly but doesn't impact core functionality.
  • Pay close attention to web/src/plugins/pipelines/useDnD.ts for the potential null access issue

Important Files Changed

File Analysis

Filename        Score        Overview
web/src/plugins/pipelines/useDnD.ts 4/5 Added helper functions to detect default destination nodes and get input stream name, with one potential null access issue
web/src/components/ConfirmDialog.vue 5/5 Enhanced dialog with optional warning message support, proper theme handling, and responsive width
web/src/components/pipeline/NodeForm/Stream.vue 5/5 Integrated warning message for default destination node deletion using new helper function
web/src/plugins/pipelines/CustomNode.vue 5/5 Added warning message support to node deletion dialog using same default destination detection
web/src/utils/pipelines/constants.ts 5/5 New constant file containing the warning message for default destination node deletion

Sequence Diagram

sequenceDiagram
    participant U as User
    participant SV as Stream.vue
    participant CN as CustomNode.vue
    participant UD as useDnD.ts
    participant CD as ConfirmDialog.vue
    participant C as Constants
    
    Note over U,C: Default Destination Node Warning Flow
    
    U->>+SV: Click delete on stream node
    SV->>+UD: checkIfDefaultDestinationNode(nodeId)
    UD->>+UD: getInputNodeStream()
    UD-->>-UD: return input stream name
    UD->>+UD: Check if node matches default destination
    UD-->>-SV: return true/false
    
    alt Is default destination node
        SV->>+C: Import defaultDestinationNodeWarningMessage
        C-->>-SV: Warning message text
        SV->>SV: Set dialog.warningMessage
    else Not default destination
        SV->>SV: Clear dialog.warningMessage
    end
    
    SV->>+CD: Show dialog with warning message
    CD->>CD: Render warning banner if message exists
    CD->>CD: Adjust dialog width dynamically
    CD-->>U: Display warning dialog
    
    alt User confirms deletion
        CD-->>-SV: Emit update:ok
        SV->>UD: deletePipelineNode(nodeId)
    else User cancels
        CD-->>SV: Emit update:cancel
    end
    
    Note over U,CN: Similar flow for CustomNode.vue
    U->>+CN: Click delete on custom node
    CN->>+UD: checkIfDefaultDestinationNode(nodeId)
    UD-->>-CN: return true/false
    CN->>+CD: Show dialog with warning
    CD-->>-U: Display warning dialog
Loading

5 files reviewed, 1 comment

Edit Code Review Agent Settings | Greptile

const nodes = pipelineObj.currentSelectedPipeline?.nodes ?? [];
const inputNode = nodes.find((node: any) => node.io_type === "input");
if(inputNode?.data.hasOwnProperty('node_type') && inputNode.data.node_type === 'stream'){
return inputNode?.data?.stream_name?.value || inputNode.data.stream_name || "";
Copy link
Contributor

Choose a reason for hiding this comment

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

logic: potential null access if inputNode is undefined

Suggested change
return inputNode?.data?.stream_name?.value || inputNode.data.stream_name || "";
return inputNode?.data?.stream_name?.value || inputNode?.data.stream_name || "";
Prompt To Fix With AI
This is a comment left during a code review.
Path: web/src/plugins/pipelines/useDnD.ts
Line: 588:588

Comment:
logic: potential null access if `inputNode` is undefined

```suggestion
      return inputNode?.data?.stream_name?.value || inputNode?.data.stream_name || "";
```

How can I resolve this? If you propose a fix, please make it concise.

@nikhilsaikethe nikhilsaikethe merged commit 48914ce into main Sep 29, 2025
29 checks passed
@nikhilsaikethe nikhilsaikethe deleted the pipeline-destination-node-warning branch September 29, 2025 16:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants