Skip to content

Conversation

@nikhilsaikethe
Copy link
Contributor

This PR fixes the below issues

  1. we need to send correct fields for preview of alert
  2. we need to show complete sql query for preview
  3. when expand only the conditions should be converted to actual preview format not all alerts will be converted

@github-actions github-actions bot added ☢️ Bug Something isn't working ✏️ Feature labels Dec 11, 2025
@github-actions
Copy link
Contributor

Failed to generate code suggestions for PR

@greptile-apps
Copy link
Contributor

greptile-apps bot commented Dec 11, 2025

Greptile Overview

Greptile Summary

This PR fixes three key issues with alert preview functionality:

  1. Correct field mapping for alert preview: Added streamFieldsMap prop to RealTimeAlert and ScheduledAlert components, ensuring proper field type information is available for SQL query generation
  2. Complete SQL query display: Introduced generatedSqlQuery computed property in AddAlert.vue that generates the full SQL query (including aggregations, GROUP BY, etc.) and passes it to FilterGroup for preview display
  3. Conditional conversion fix: Modified alert list to only convert condition formats when expanding an alert (lazy conversion), rather than converting all alerts on page load

Key improvements:

  • Created shared conditionsFormatter utility with comprehensive documentation explaining V2 format logic
  • Added extensive test coverage for the new formatter utility
  • Performance optimization: Alert list now defers condition conversion until user expands an alert
  • Three preview modes in FilterGroup: full SQL query (for alerts), WHERE clause only (fallback), and display format (for pipelines)

Confidence Score: 4/5

  • This PR is safe to merge with minor style improvements recommended
  • The implementation is solid with comprehensive tests, well-documented code, and clear separation of concerns. Minor deduction for code duplication in AlertList.vue that could be refactored for better maintainability, but this doesn't affect functionality or introduce bugs.
  • web/src/components/alerts/AlertList.vue has duplicated condition conversion logic that could be extracted to a helper function

Important Files Changed

File Analysis

Filename Score Overview
web/src/utils/alerts/conditionsFormatter.ts 5/5 New utility file for formatting V2 condition structures. Well-documented with extensive comments explaining the logic. No issues found.
web/src/components/alerts/AddAlert.vue 5/5 Added generatedSqlQuery computed property and passes streamFieldsMap and generatedSqlQuery to child components for proper SQL preview.
web/src/components/alerts/FilterGroup.vue 5/5 Enhanced preview logic to support three modes: display format, SQL WHERE clause, and full SQL query. Uses shared utility for consistency.
web/src/components/alerts/AlertList.vue 4/5 Implemented lazy conversion of alert conditions on expand. Improved performance by deferring conversion until needed. Minor concern: duplicated conversion logic in triggerExpand (see comment).

Sequence Diagram

sequenceDiagram
    participant User
    participant AddAlert
    participant RealTimeAlert/ScheduledAlert
    participant FilterGroup
    participant conditionsFormatter
    participant alertQueryBuilder

    Note over User,alertQueryBuilder: Alert Preview Flow

    User->>AddAlert: Edit alert conditions
    AddAlert->>AddAlert: formData.query_condition.conditions updated
    
    Note over AddAlert: Compute generatedSqlQuery
    AddAlert->>alertQueryBuilder: generateSqlQuery(formData, streamFieldsMap)
    alertQueryBuilder->>conditionsFormatter: buildConditionsString(conditions, {sqlMode:true})
    conditionsFormatter-->>alertQueryBuilder: WHERE clause
    alertQueryBuilder-->>AddAlert: Full SQL query
    
    AddAlert->>RealTimeAlert/ScheduledAlert: Pass streamFieldsMap + generatedSqlQuery
    RealTimeAlert/ScheduledAlert->>FilterGroup: Pass streamFieldsMap + generatedSqlQuery + showSqlPreview
    
    Note over FilterGroup: Preview String Computation
    alt Full SQL Query Available
        FilterGroup->>FilterGroup: Show sqlQuery prop (complete SQL)
    else showSqlPreview is true
        FilterGroup->>conditionsFormatter: buildConditionsString({sqlMode:true, addWherePrefix:true})
        conditionsFormatter-->>FilterGroup: WHERE clause only
    else Default Display Mode
        FilterGroup->>conditionsFormatter: buildConditionsString({sqlMode:false})
        conditionsFormatter-->>FilterGroup: Display format (lowercase)
    end
    
    FilterGroup-->>User: Display preview string

    Note over User,alertQueryBuilder: Alert List Lazy Conversion Flow
    
    User->>AlertList: Load alerts page
    AlertList->>AlertList: Store rawCondition without conversion
    Note over AlertList: Performance optimization:<br/>No conversion on list load
    
    User->>AlertList: Click expand on alert
    AlertList->>AlertList: triggerExpand(alert)
    
    Note over AlertList: Lazy conversion on-demand
    alt V2 format
        AlertList->>conditionsFormatter: buildConditionsString(v2Format, {sqlMode:false})
        conditionsFormatter-->>AlertList: Display string
    else V1 format
        AlertList->>AlertList: transformToExpression(v1Format)
    else V0 format
        AlertList->>AlertList: Manual conversion (flat array)
    end
    
    AlertList-->>User: Show alert details with converted conditions
Loading

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.

9 files reviewed, 1 comment

Edit Code Review Agent Settings | Greptile

Comment on lines +987 to +1021
// This improves performance by avoiding conversion of all alerts on list load
let displayConditions = "--";
if (alert.rawCondition && Object.keys(alert.rawCondition).length) {
if (alert.rawCondition.type == 'custom') {
const conditionData = alert.rawCondition.conditions;
// Detect format by structure, not by version field (more reliable)
if (conditionData?.filterType === 'group') {
// V2 format: {filterType: "group", logicalOperator: "AND", conditions: [...]}
displayConditions = transformV2ToExpression(conditionData);
} else if (conditionData?.version === 2 && conditionData?.conditions) {
// V2 format with version wrapper: {version: 2, conditions: {filterType: "group", ...}}
displayConditions = transformV2ToExpression(conditionData.conditions);
} else if (conditionData?.or || conditionData?.and) {
// V1 format: {or: [...]} or {and: [...]}
displayConditions = transformToExpression(conditionData);
} else if (Array.isArray(conditionData) && conditionData.length > 0) {
// V0 format (legacy): flat array [{column, operator, value}, ...]
// V0 had implicit AND between all conditions (no groups)
const parts = conditionData.map((item: any) => {
const column = item.column || 'field';
const operator = item.operator || '=';
const value = typeof item.value === 'string' ? `'${item.value}'` : item.value;
return `${column} ${operator} ${value}`;
});
displayConditions = parts.length > 0 ? `(${parts.join(' AND ')})` : '--';
} else {
// Unknown format or empty
displayConditions = typeof conditionData === 'string' ? conditionData : '--';
}
} else if (alert.rawCondition.sql) {
displayConditions = alert.rawCondition.sql;
} else if (alert.rawCondition.promql) {
displayConditions = alert.rawCondition.promql;
}
Copy link
Contributor

Choose a reason for hiding this comment

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

style: duplicated conversion logic that could be extracted to a helper function

The condition format detection and conversion logic (V0/V1/V2 format handling) is duplicated here and in transformV2ToExpression. Consider extracting this to a shared helper function for better maintainability.

Suggested change
// This improves performance by avoiding conversion of all alerts on list load
let displayConditions = "--";
if (alert.rawCondition && Object.keys(alert.rawCondition).length) {
if (alert.rawCondition.type == 'custom') {
const conditionData = alert.rawCondition.conditions;
// Detect format by structure, not by version field (more reliable)
if (conditionData?.filterType === 'group') {
// V2 format: {filterType: "group", logicalOperator: "AND", conditions: [...]}
displayConditions = transformV2ToExpression(conditionData);
} else if (conditionData?.version === 2 && conditionData?.conditions) {
// V2 format with version wrapper: {version: 2, conditions: {filterType: "group", ...}}
displayConditions = transformV2ToExpression(conditionData.conditions);
} else if (conditionData?.or || conditionData?.and) {
// V1 format: {or: [...]} or {and: [...]}
displayConditions = transformToExpression(conditionData);
} else if (Array.isArray(conditionData) && conditionData.length > 0) {
// V0 format (legacy): flat array [{column, operator, value}, ...]
// V0 had implicit AND between all conditions (no groups)
const parts = conditionData.map((item: any) => {
const column = item.column || 'field';
const operator = item.operator || '=';
const value = typeof item.value === 'string' ? `'${item.value}'` : item.value;
return `${column} ${operator} ${value}`;
});
displayConditions = parts.length > 0 ? `(${parts.join(' AND ')})` : '--';
} else {
// Unknown format or empty
displayConditions = typeof conditionData === 'string' ? conditionData : '--';
}
} else if (alert.rawCondition.sql) {
displayConditions = alert.rawCondition.sql;
} else if (alert.rawCondition.promql) {
displayConditions = alert.rawCondition.promql;
}
// LAZY CONVERSION: Convert conditions on-demand only when expanding
// This improves performance by avoiding conversion of all alerts on list load
let displayConditions = "--";
if (alert.rawCondition && Object.keys(alert.rawCondition).length) {
displayConditions = convertConditionsToDisplay(alert.rawCondition);
}
// Helper function (can be extracted to utils)
function convertConditionsToDisplay(rawCondition: any): string {
if (rawCondition.type === 'custom') {
const conditionData = rawCondition.conditions;
if (conditionData?.filterType === 'group') {
return transformV2ToExpression(conditionData);
} else if (conditionData?.version === 2 && conditionData?.conditions) {
return transformV2ToExpression(conditionData.conditions);
} else if (conditionData?.or || conditionData?.and) {
return transformToExpression(conditionData);
} else if (Array.isArray(conditionData) && conditionData.length > 0) {
const parts = conditionData.map((item: any) => {
const column = item.column || 'field';
const operator = item.operator || '=';
const value = typeof item.value === 'string' ? `'${item.value}'` : item.value;
return `${column} ${operator} ${value}`;
});
return parts.length > 0 ? `(${parts.join(' AND ')})` : '--';
}
return typeof conditionData === 'string' ? conditionData : '--';
} else if (rawCondition.sql) {
return rawCondition.sql;
} else if (rawCondition.promql) {
return rawCondition.promql;
}
return '--';
}
Prompt To Fix With AI
This is a comment left during a code review.
Path: web/src/components/alerts/AlertList.vue
Line: 987:1021

Comment:
**style:** duplicated conversion logic that could be extracted to a helper function

The condition format detection and conversion logic (V0/V1/V2 format handling) is duplicated here and in `transformV2ToExpression`. Consider extracting this to a shared helper function for better maintainability.

```suggestion
      // LAZY CONVERSION: Convert conditions on-demand only when expanding
      // This improves performance by avoiding conversion of all alerts on list load
      let displayConditions = "--";
      if (alert.rawCondition && Object.keys(alert.rawCondition).length) {
        displayConditions = convertConditionsToDisplay(alert.rawCondition);
      }

      // Helper function (can be extracted to utils)
      function convertConditionsToDisplay(rawCondition: any): string {
        if (rawCondition.type === 'custom') {
          const conditionData = rawCondition.conditions;
          if (conditionData?.filterType === 'group') {
            return transformV2ToExpression(conditionData);
          } else if (conditionData?.version === 2 && conditionData?.conditions) {
            return transformV2ToExpression(conditionData.conditions);
          } else if (conditionData?.or || conditionData?.and) {
            return transformToExpression(conditionData);
          } else if (Array.isArray(conditionData) && conditionData.length > 0) {
            const parts = conditionData.map((item: any) => {
              const column = item.column || 'field';
              const operator = item.operator || '=';
              const value = typeof item.value === 'string' ? `'${item.value}'` : item.value;
              return `${column} ${operator} ${value}`;
            });
            return parts.length > 0 ? `(${parts.join(' AND ')})` : '--';
          }
          return typeof conditionData === 'string' ? conditionData : '--';
        } else if (rawCondition.sql) {
          return rawCondition.sql;
        } else if (rawCondition.promql) {
          return rawCondition.promql;
        }
        return '--';
      }
```

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

nikhilsaikethe and others added 12 commits December 11, 2025 14:05
Auto-generated translation updates from English source file.

🤖 Generated with automated translation workflow
Auto-generated translation updates from English source file.

🤖 Generated with automated translation workflow
Auto-generated translation updates from English source file.

🤖 Generated with automated translation workflow
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

☢️ Bug Something isn't working ✏️ Feature

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants