From c37d6c3785d6006ab6ed94c1a439dae6c07abd8b Mon Sep 17 00:00:00 2001 From: Palash Gupta Date: Tue, 15 Aug 2023 06:37:26 +0530 Subject: [PATCH] feat: added the support of y axis unit and threshold unit in the alerts page (#3268) --- frontend/public/locales/en-GB/alerts.json | 223 +++--- frontend/public/locales/en/alerts.json | 223 +++--- .../src/container/CreateAlertRule/defaults.ts | 4 + .../FormAlertRules/ChartPreview/config.ts | 98 +++ .../FormAlertRules/ChartPreview/index.tsx | 25 +- .../FormAlertRules/ChartPreview/utils.test.ts | 105 +++ .../FormAlertRules/ChartPreview/utils.ts | 54 ++ .../container/FormAlertRules/RuleOptions.tsx | 105 ++- .../src/container/FormAlertRules/index.tsx | 26 +- .../src/container/FormAlertRules/styles.ts | 4 + .../RightContainer/alertFomatCategories.ts | 121 +++ .../RightContainer/dataFormatCategories.ts | 695 ++++++++++-------- .../NewWidget/RightContainer/types.ts | 364 +++++++++ .../BuilderUnitsFilter/BuilderUnits.tsx | 48 ++ .../filters/BuilderUnitsFilter/config.ts | 10 + .../filters/BuilderUnitsFilter/index.ts | 1 + .../filters/BuilderUnitsFilter/styles.ts | 11 + .../filters/BuilderUnitsFilter/types.ts | 3 + .../filters/BuilderUnitsFilter/utils.ts | 6 + .../container/QueryBuilder/filters/index.ts | 1 + .../mapQueryDataFromApi.ts | 1 + frontend/src/providers/QueryBuilder.tsx | 16 + .../actions/dashboard/getQueryResults.ts | 1 + .../src/types/api/alerts/compositeQuery.ts | 2 + frontend/src/types/api/alerts/def.ts | 1 + .../api/queryBuilder/queryBuilderData.ts | 2 + frontend/src/types/common/queryBuilder.ts | 2 + 27 files changed, 1568 insertions(+), 584 deletions(-) create mode 100644 frontend/src/container/FormAlertRules/ChartPreview/config.ts create mode 100644 frontend/src/container/FormAlertRules/ChartPreview/utils.test.ts create mode 100644 frontend/src/container/FormAlertRules/ChartPreview/utils.ts create mode 100644 frontend/src/container/NewWidget/RightContainer/alertFomatCategories.ts create mode 100644 frontend/src/container/NewWidget/RightContainer/types.ts create mode 100644 frontend/src/container/QueryBuilder/filters/BuilderUnitsFilter/BuilderUnits.tsx create mode 100644 frontend/src/container/QueryBuilder/filters/BuilderUnitsFilter/config.ts create mode 100644 frontend/src/container/QueryBuilder/filters/BuilderUnitsFilter/index.ts create mode 100644 frontend/src/container/QueryBuilder/filters/BuilderUnitsFilter/styles.ts create mode 100644 frontend/src/container/QueryBuilder/filters/BuilderUnitsFilter/types.ts create mode 100644 frontend/src/container/QueryBuilder/filters/BuilderUnitsFilter/utils.ts diff --git a/frontend/public/locales/en-GB/alerts.json b/frontend/public/locales/en-GB/alerts.json index b5c769a021..816b71e563 100644 --- a/frontend/public/locales/en-GB/alerts.json +++ b/frontend/public/locales/en-GB/alerts.json @@ -1,112 +1,113 @@ { - "target_missing": "Please enter a threshold to proceed", - "rule_test_fired": "Test notification sent successfully", - "no_alerts_found": "No alerts found during the evaluation. This happens when rule condition is unsatisfied. You may adjust the rule threshold and retry.", - "button_testrule": "Test Notification", - "label_channel_select": "Notification Channels", - "placeholder_channel_select": "select one or more channels", - "channel_select_tooltip": "Leave empty to send this alert on all the configured channels", - "preview_chart_unexpected_error": "An unexpeced error occurred updating the chart, please check your query.", - "preview_chart_threshold_label": "Threshold", - "placeholder_label_key_pair": "Click here to enter a label (key value pairs)", - "button_yes": "Yes", - "button_no": "No", - "remove_label_confirm": "This action will remove all the labels. Do you want to proceed?", - "remove_label_success": "Labels cleared", - "alert_form_step1": "Step 1 - Define the metric", - "alert_form_step2": "Step 2 - Define Alert Conditions", - "alert_form_step3": "Step 3 - Alert Configuration", - "metric_query_max_limit": "Can not create query. You can create maximum of 5 queries", - "confirm_save_title": "Save Changes", - "confirm_save_content_part1": "Your alert built with", - "confirm_save_content_part2": "query will be saved. Press OK to confirm.", - "unexpected_error": "Sorry, an unexpected error occurred. Please contact your admin", - "rule_created": "Rule created successfully", - "rule_edited": "Rule edited successfully", - "expression_missing": "expression is missing in {{where}}", - "metricname_missing": "metric name is missing in {{where}}", - "condition_required": "at least one metric condition is required", - "alertname_required": "alert name is required", - "promql_required": "promql expression is required when query format is set to PromQL", - "chquery_required": "query is required when query format is set to ClickHouse", - "button_savechanges": "Save Rule", - "button_createrule": "Create Rule", - "button_returntorules": "Return to rules", - "button_cancelchanges": "Cancel", - "button_discard": "Discard", - "text_condition1": "Send a notification when the metric is", - "text_condition2": "the threshold", - "text_condition3": "during the last", - "option_5min": "5 mins", - "option_10min": "10 mins", - "option_15min": "15 mins", - "option_60min": "60 mins", - "option_4hours": "4 hours", - "option_24hours": "24 hours", - "field_threshold": "Alert Threshold", - "option_allthetimes": "all the times", - "option_atleastonce": "at least once", - "option_onaverage": "on average", - "option_intotal": "in total", - "option_above": "above", - "option_below": "below", - "option_equal": "is equal to", - "option_notequal": "not equal to", - "button_query": "Query", - "button_formula": "Formula", - "tab_qb": "Query Builder", - "tab_promql": "PromQL", - "tab_chquery": "ClickHouse Query", - "title_confirm": "Confirm", - "button_ok": "Yes", - "button_cancel": "No", - "field_promql_expr": "PromQL Expression", - "field_alert_name": "Alert Name", - "field_alert_desc": "Alert Description", - "field_labels": "Labels", - "field_severity": "Severity", - "option_critical": "Critical", - "option_error": "Error", - "option_warning": "Warning", - "option_info": "Info", - "user_guide_headline": "Steps to create an Alert", - "user_guide_qb_step1": "Step 1 - Define the metric", - "user_guide_qb_step1a": "Choose a metric which you want to create an alert on", - "user_guide_qb_step1b": "Filter it based on WHERE field or GROUPBY if needed", - "user_guide_qb_step1c": "Apply an aggregatiion function like COUNT, SUM, etc. or choose NOOP to plot the raw metric", - "user_guide_qb_step1d": "Create a formula based on Queries if needed", - "user_guide_qb_step2": "Step 2 - Define Alert Conditions", - "user_guide_qb_step2a": "Select the evaluation interval, threshold type and whether you want to alert above/below a value", - "user_guide_qb_step2b": "Enter the Alert threshold", - "user_guide_qb_step3": "Step 3 -Alert Configuration", - "user_guide_qb_step3a": "Set alert severity, name and descriptions", - "user_guide_qb_step3b": "Add tags to the alert in the Label field if needed", - "user_guide_pql_step1": "Step 1 - Define the metric", - "user_guide_pql_step1a": "Write a PromQL query for the metric", - "user_guide_pql_step1b": "Format the legends based on labels you want to highlight", - "user_guide_pql_step2": "Step 2 - Define Alert Conditions", - "user_guide_pql_step2a": "Select the threshold type and whether you want to alert above/below a value", - "user_guide_pql_step2b": "Enter the Alert threshold", - "user_guide_pql_step3": "Step 3 -Alert Configuration", - "user_guide_pql_step3a": "Set alert severity, name and descriptions", - "user_guide_pql_step3b": "Add tags to the alert in the Label field if needed", - "user_guide_ch_step1": "Step 1 - Define the metric", - "user_guide_ch_step1a": "Write a Clickhouse query for alert evaluation. Follow <0>this tutorial to learn about query format and supported vars.", - "user_guide_ch_step1b": "Format the legends based on labels you want to highlight in the preview chart", - "user_guide_ch_step2": "Step 2 - Define Alert Conditions", - "user_guide_ch_step2a": "Select the threshold type and whether you want to alert above/below a value", - "user_guide_ch_step2b": "Enter the Alert threshold", - "user_guide_ch_step3": "Step 3 -Alert Configuration", - "user_guide_ch_step3a": "Set alert severity, name and descriptions", - "user_guide_ch_step3b": "Add tags to the alert in the Label field if needed", - "user_tooltip_more_help": "More details on how to create alerts", - "choose_alert_type": "Choose a type for the alert:", - "metric_based_alert": "Metric based Alert", - "metric_based_alert_desc": "Send a notification when a condition occurs in the metric data", - "log_based_alert": "Log-based Alert", - "log_based_alert_desc": "Send a notification when a condition occurs in the logs data.", - "traces_based_alert": "Trace-based Alert", - "traces_based_alert_desc": "Send a notification when a condition occurs in the traces data.", - "exceptions_based_alert": "Exceptions-based Alert", - "exceptions_based_alert_desc": "Send a notification when a condition occurs in the exceptions data." -} \ No newline at end of file + "target_missing": "Please enter a threshold to proceed", + "rule_test_fired": "Test notification sent successfully", + "no_alerts_found": "No alerts found during the evaluation. This happens when rule condition is unsatisfied. You may adjust the rule threshold and retry.", + "button_testrule": "Test Notification", + "label_channel_select": "Notification Channels", + "placeholder_channel_select": "select one or more channels", + "channel_select_tooltip": "Leave empty to send this alert on all the configured channels", + "preview_chart_unexpected_error": "An unexpeced error occurred updating the chart, please check your query.", + "preview_chart_threshold_label": "Threshold", + "placeholder_label_key_pair": "Click here to enter a label (key value pairs)", + "button_yes": "Yes", + "button_no": "No", + "remove_label_confirm": "This action will remove all the labels. Do you want to proceed?", + "remove_label_success": "Labels cleared", + "alert_form_step1": "Step 1 - Define the metric", + "alert_form_step2": "Step 2 - Define Alert Conditions", + "alert_form_step3": "Step 3 - Alert Configuration", + "metric_query_max_limit": "Can not create query. You can create maximum of 5 queries", + "confirm_save_title": "Save Changes", + "confirm_save_content_part1": "Your alert built with", + "confirm_save_content_part2": "query will be saved. Press OK to confirm.", + "unexpected_error": "Sorry, an unexpected error occurred. Please contact your admin", + "rule_created": "Rule created successfully", + "rule_edited": "Rule edited successfully", + "expression_missing": "expression is missing in {{where}}", + "metricname_missing": "metric name is missing in {{where}}", + "condition_required": "at least one metric condition is required", + "alertname_required": "alert name is required", + "promql_required": "promql expression is required when query format is set to PromQL", + "chquery_required": "query is required when query format is set to ClickHouse", + "button_savechanges": "Save Rule", + "button_createrule": "Create Rule", + "button_returntorules": "Return to rules", + "button_cancelchanges": "Cancel", + "button_discard": "Discard", + "text_condition1": "Send a notification when the metric is", + "text_condition2": "the threshold", + "text_condition3": "during the last", + "option_5min": "5 mins", + "option_10min": "10 mins", + "option_15min": "15 mins", + "option_60min": "60 mins", + "option_4hours": "4 hours", + "option_24hours": "24 hours", + "field_threshold": "Alert Threshold", + "option_allthetimes": "all the times", + "option_atleastonce": "at least once", + "option_onaverage": "on average", + "option_intotal": "in total", + "option_above": "above", + "option_below": "below", + "option_equal": "is equal to", + "option_notequal": "not equal to", + "button_query": "Query", + "button_formula": "Formula", + "tab_qb": "Query Builder", + "tab_promql": "PromQL", + "tab_chquery": "ClickHouse Query", + "title_confirm": "Confirm", + "button_ok": "Yes", + "button_cancel": "No", + "field_promql_expr": "PromQL Expression", + "field_alert_name": "Alert Name", + "field_alert_desc": "Alert Description", + "field_labels": "Labels", + "field_severity": "Severity", + "option_critical": "Critical", + "option_error": "Error", + "option_warning": "Warning", + "option_info": "Info", + "user_guide_headline": "Steps to create an Alert", + "user_guide_qb_step1": "Step 1 - Define the metric", + "user_guide_qb_step1a": "Choose a metric which you want to create an alert on", + "user_guide_qb_step1b": "Filter it based on WHERE field or GROUPBY if needed", + "user_guide_qb_step1c": "Apply an aggregatiion function like COUNT, SUM, etc. or choose NOOP to plot the raw metric", + "user_guide_qb_step1d": "Create a formula based on Queries if needed", + "user_guide_qb_step2": "Step 2 - Define Alert Conditions", + "user_guide_qb_step2a": "Select the evaluation interval, threshold type and whether you want to alert above/below a value", + "user_guide_qb_step2b": "Enter the Alert threshold", + "user_guide_qb_step3": "Step 3 -Alert Configuration", + "user_guide_qb_step3a": "Set alert severity, name and descriptions", + "user_guide_qb_step3b": "Add tags to the alert in the Label field if needed", + "user_guide_pql_step1": "Step 1 - Define the metric", + "user_guide_pql_step1a": "Write a PromQL query for the metric", + "user_guide_pql_step1b": "Format the legends based on labels you want to highlight", + "user_guide_pql_step2": "Step 2 - Define Alert Conditions", + "user_guide_pql_step2a": "Select the threshold type and whether you want to alert above/below a value", + "user_guide_pql_step2b": "Enter the Alert threshold", + "user_guide_pql_step3": "Step 3 -Alert Configuration", + "user_guide_pql_step3a": "Set alert severity, name and descriptions", + "user_guide_pql_step3b": "Add tags to the alert in the Label field if needed", + "user_guide_ch_step1": "Step 1 - Define the metric", + "user_guide_ch_step1a": "Write a Clickhouse query for alert evaluation. Follow <0>this tutorial to learn about query format and supported vars.", + "user_guide_ch_step1b": "Format the legends based on labels you want to highlight in the preview chart", + "user_guide_ch_step2": "Step 2 - Define Alert Conditions", + "user_guide_ch_step2a": "Select the threshold type and whether you want to alert above/below a value", + "user_guide_ch_step2b": "Enter the Alert threshold", + "user_guide_ch_step3": "Step 3 -Alert Configuration", + "user_guide_ch_step3a": "Set alert severity, name and descriptions", + "user_guide_ch_step3b": "Add tags to the alert in the Label field if needed", + "user_tooltip_more_help": "More details on how to create alerts", + "choose_alert_type": "Choose a type for the alert:", + "metric_based_alert": "Metric based Alert", + "metric_based_alert_desc": "Send a notification when a condition occurs in the metric data", + "log_based_alert": "Log-based Alert", + "log_based_alert_desc": "Send a notification when a condition occurs in the logs data.", + "traces_based_alert": "Trace-based Alert", + "traces_based_alert_desc": "Send a notification when a condition occurs in the traces data.", + "exceptions_based_alert": "Exceptions-based Alert", + "exceptions_based_alert_desc": "Send a notification when a condition occurs in the exceptions data.", + "field_unit": "Threshold unit" +} diff --git a/frontend/public/locales/en/alerts.json b/frontend/public/locales/en/alerts.json index b5c769a021..816b71e563 100644 --- a/frontend/public/locales/en/alerts.json +++ b/frontend/public/locales/en/alerts.json @@ -1,112 +1,113 @@ { - "target_missing": "Please enter a threshold to proceed", - "rule_test_fired": "Test notification sent successfully", - "no_alerts_found": "No alerts found during the evaluation. This happens when rule condition is unsatisfied. You may adjust the rule threshold and retry.", - "button_testrule": "Test Notification", - "label_channel_select": "Notification Channels", - "placeholder_channel_select": "select one or more channels", - "channel_select_tooltip": "Leave empty to send this alert on all the configured channels", - "preview_chart_unexpected_error": "An unexpeced error occurred updating the chart, please check your query.", - "preview_chart_threshold_label": "Threshold", - "placeholder_label_key_pair": "Click here to enter a label (key value pairs)", - "button_yes": "Yes", - "button_no": "No", - "remove_label_confirm": "This action will remove all the labels. Do you want to proceed?", - "remove_label_success": "Labels cleared", - "alert_form_step1": "Step 1 - Define the metric", - "alert_form_step2": "Step 2 - Define Alert Conditions", - "alert_form_step3": "Step 3 - Alert Configuration", - "metric_query_max_limit": "Can not create query. You can create maximum of 5 queries", - "confirm_save_title": "Save Changes", - "confirm_save_content_part1": "Your alert built with", - "confirm_save_content_part2": "query will be saved. Press OK to confirm.", - "unexpected_error": "Sorry, an unexpected error occurred. Please contact your admin", - "rule_created": "Rule created successfully", - "rule_edited": "Rule edited successfully", - "expression_missing": "expression is missing in {{where}}", - "metricname_missing": "metric name is missing in {{where}}", - "condition_required": "at least one metric condition is required", - "alertname_required": "alert name is required", - "promql_required": "promql expression is required when query format is set to PromQL", - "chquery_required": "query is required when query format is set to ClickHouse", - "button_savechanges": "Save Rule", - "button_createrule": "Create Rule", - "button_returntorules": "Return to rules", - "button_cancelchanges": "Cancel", - "button_discard": "Discard", - "text_condition1": "Send a notification when the metric is", - "text_condition2": "the threshold", - "text_condition3": "during the last", - "option_5min": "5 mins", - "option_10min": "10 mins", - "option_15min": "15 mins", - "option_60min": "60 mins", - "option_4hours": "4 hours", - "option_24hours": "24 hours", - "field_threshold": "Alert Threshold", - "option_allthetimes": "all the times", - "option_atleastonce": "at least once", - "option_onaverage": "on average", - "option_intotal": "in total", - "option_above": "above", - "option_below": "below", - "option_equal": "is equal to", - "option_notequal": "not equal to", - "button_query": "Query", - "button_formula": "Formula", - "tab_qb": "Query Builder", - "tab_promql": "PromQL", - "tab_chquery": "ClickHouse Query", - "title_confirm": "Confirm", - "button_ok": "Yes", - "button_cancel": "No", - "field_promql_expr": "PromQL Expression", - "field_alert_name": "Alert Name", - "field_alert_desc": "Alert Description", - "field_labels": "Labels", - "field_severity": "Severity", - "option_critical": "Critical", - "option_error": "Error", - "option_warning": "Warning", - "option_info": "Info", - "user_guide_headline": "Steps to create an Alert", - "user_guide_qb_step1": "Step 1 - Define the metric", - "user_guide_qb_step1a": "Choose a metric which you want to create an alert on", - "user_guide_qb_step1b": "Filter it based on WHERE field or GROUPBY if needed", - "user_guide_qb_step1c": "Apply an aggregatiion function like COUNT, SUM, etc. or choose NOOP to plot the raw metric", - "user_guide_qb_step1d": "Create a formula based on Queries if needed", - "user_guide_qb_step2": "Step 2 - Define Alert Conditions", - "user_guide_qb_step2a": "Select the evaluation interval, threshold type and whether you want to alert above/below a value", - "user_guide_qb_step2b": "Enter the Alert threshold", - "user_guide_qb_step3": "Step 3 -Alert Configuration", - "user_guide_qb_step3a": "Set alert severity, name and descriptions", - "user_guide_qb_step3b": "Add tags to the alert in the Label field if needed", - "user_guide_pql_step1": "Step 1 - Define the metric", - "user_guide_pql_step1a": "Write a PromQL query for the metric", - "user_guide_pql_step1b": "Format the legends based on labels you want to highlight", - "user_guide_pql_step2": "Step 2 - Define Alert Conditions", - "user_guide_pql_step2a": "Select the threshold type and whether you want to alert above/below a value", - "user_guide_pql_step2b": "Enter the Alert threshold", - "user_guide_pql_step3": "Step 3 -Alert Configuration", - "user_guide_pql_step3a": "Set alert severity, name and descriptions", - "user_guide_pql_step3b": "Add tags to the alert in the Label field if needed", - "user_guide_ch_step1": "Step 1 - Define the metric", - "user_guide_ch_step1a": "Write a Clickhouse query for alert evaluation. Follow <0>this tutorial to learn about query format and supported vars.", - "user_guide_ch_step1b": "Format the legends based on labels you want to highlight in the preview chart", - "user_guide_ch_step2": "Step 2 - Define Alert Conditions", - "user_guide_ch_step2a": "Select the threshold type and whether you want to alert above/below a value", - "user_guide_ch_step2b": "Enter the Alert threshold", - "user_guide_ch_step3": "Step 3 -Alert Configuration", - "user_guide_ch_step3a": "Set alert severity, name and descriptions", - "user_guide_ch_step3b": "Add tags to the alert in the Label field if needed", - "user_tooltip_more_help": "More details on how to create alerts", - "choose_alert_type": "Choose a type for the alert:", - "metric_based_alert": "Metric based Alert", - "metric_based_alert_desc": "Send a notification when a condition occurs in the metric data", - "log_based_alert": "Log-based Alert", - "log_based_alert_desc": "Send a notification when a condition occurs in the logs data.", - "traces_based_alert": "Trace-based Alert", - "traces_based_alert_desc": "Send a notification when a condition occurs in the traces data.", - "exceptions_based_alert": "Exceptions-based Alert", - "exceptions_based_alert_desc": "Send a notification when a condition occurs in the exceptions data." -} \ No newline at end of file + "target_missing": "Please enter a threshold to proceed", + "rule_test_fired": "Test notification sent successfully", + "no_alerts_found": "No alerts found during the evaluation. This happens when rule condition is unsatisfied. You may adjust the rule threshold and retry.", + "button_testrule": "Test Notification", + "label_channel_select": "Notification Channels", + "placeholder_channel_select": "select one or more channels", + "channel_select_tooltip": "Leave empty to send this alert on all the configured channels", + "preview_chart_unexpected_error": "An unexpeced error occurred updating the chart, please check your query.", + "preview_chart_threshold_label": "Threshold", + "placeholder_label_key_pair": "Click here to enter a label (key value pairs)", + "button_yes": "Yes", + "button_no": "No", + "remove_label_confirm": "This action will remove all the labels. Do you want to proceed?", + "remove_label_success": "Labels cleared", + "alert_form_step1": "Step 1 - Define the metric", + "alert_form_step2": "Step 2 - Define Alert Conditions", + "alert_form_step3": "Step 3 - Alert Configuration", + "metric_query_max_limit": "Can not create query. You can create maximum of 5 queries", + "confirm_save_title": "Save Changes", + "confirm_save_content_part1": "Your alert built with", + "confirm_save_content_part2": "query will be saved. Press OK to confirm.", + "unexpected_error": "Sorry, an unexpected error occurred. Please contact your admin", + "rule_created": "Rule created successfully", + "rule_edited": "Rule edited successfully", + "expression_missing": "expression is missing in {{where}}", + "metricname_missing": "metric name is missing in {{where}}", + "condition_required": "at least one metric condition is required", + "alertname_required": "alert name is required", + "promql_required": "promql expression is required when query format is set to PromQL", + "chquery_required": "query is required when query format is set to ClickHouse", + "button_savechanges": "Save Rule", + "button_createrule": "Create Rule", + "button_returntorules": "Return to rules", + "button_cancelchanges": "Cancel", + "button_discard": "Discard", + "text_condition1": "Send a notification when the metric is", + "text_condition2": "the threshold", + "text_condition3": "during the last", + "option_5min": "5 mins", + "option_10min": "10 mins", + "option_15min": "15 mins", + "option_60min": "60 mins", + "option_4hours": "4 hours", + "option_24hours": "24 hours", + "field_threshold": "Alert Threshold", + "option_allthetimes": "all the times", + "option_atleastonce": "at least once", + "option_onaverage": "on average", + "option_intotal": "in total", + "option_above": "above", + "option_below": "below", + "option_equal": "is equal to", + "option_notequal": "not equal to", + "button_query": "Query", + "button_formula": "Formula", + "tab_qb": "Query Builder", + "tab_promql": "PromQL", + "tab_chquery": "ClickHouse Query", + "title_confirm": "Confirm", + "button_ok": "Yes", + "button_cancel": "No", + "field_promql_expr": "PromQL Expression", + "field_alert_name": "Alert Name", + "field_alert_desc": "Alert Description", + "field_labels": "Labels", + "field_severity": "Severity", + "option_critical": "Critical", + "option_error": "Error", + "option_warning": "Warning", + "option_info": "Info", + "user_guide_headline": "Steps to create an Alert", + "user_guide_qb_step1": "Step 1 - Define the metric", + "user_guide_qb_step1a": "Choose a metric which you want to create an alert on", + "user_guide_qb_step1b": "Filter it based on WHERE field or GROUPBY if needed", + "user_guide_qb_step1c": "Apply an aggregatiion function like COUNT, SUM, etc. or choose NOOP to plot the raw metric", + "user_guide_qb_step1d": "Create a formula based on Queries if needed", + "user_guide_qb_step2": "Step 2 - Define Alert Conditions", + "user_guide_qb_step2a": "Select the evaluation interval, threshold type and whether you want to alert above/below a value", + "user_guide_qb_step2b": "Enter the Alert threshold", + "user_guide_qb_step3": "Step 3 -Alert Configuration", + "user_guide_qb_step3a": "Set alert severity, name and descriptions", + "user_guide_qb_step3b": "Add tags to the alert in the Label field if needed", + "user_guide_pql_step1": "Step 1 - Define the metric", + "user_guide_pql_step1a": "Write a PromQL query for the metric", + "user_guide_pql_step1b": "Format the legends based on labels you want to highlight", + "user_guide_pql_step2": "Step 2 - Define Alert Conditions", + "user_guide_pql_step2a": "Select the threshold type and whether you want to alert above/below a value", + "user_guide_pql_step2b": "Enter the Alert threshold", + "user_guide_pql_step3": "Step 3 -Alert Configuration", + "user_guide_pql_step3a": "Set alert severity, name and descriptions", + "user_guide_pql_step3b": "Add tags to the alert in the Label field if needed", + "user_guide_ch_step1": "Step 1 - Define the metric", + "user_guide_ch_step1a": "Write a Clickhouse query for alert evaluation. Follow <0>this tutorial to learn about query format and supported vars.", + "user_guide_ch_step1b": "Format the legends based on labels you want to highlight in the preview chart", + "user_guide_ch_step2": "Step 2 - Define Alert Conditions", + "user_guide_ch_step2a": "Select the threshold type and whether you want to alert above/below a value", + "user_guide_ch_step2b": "Enter the Alert threshold", + "user_guide_ch_step3": "Step 3 -Alert Configuration", + "user_guide_ch_step3a": "Set alert severity, name and descriptions", + "user_guide_ch_step3b": "Add tags to the alert in the Label field if needed", + "user_tooltip_more_help": "More details on how to create alerts", + "choose_alert_type": "Choose a type for the alert:", + "metric_based_alert": "Metric based Alert", + "metric_based_alert_desc": "Send a notification when a condition occurs in the metric data", + "log_based_alert": "Log-based Alert", + "log_based_alert_desc": "Send a notification when a condition occurs in the logs data.", + "traces_based_alert": "Trace-based Alert", + "traces_based_alert_desc": "Send a notification when a condition occurs in the traces data.", + "exceptions_based_alert": "Exceptions-based Alert", + "exceptions_based_alert_desc": "Send a notification when a condition occurs in the exceptions data.", + "field_unit": "Threshold unit" +} diff --git a/frontend/src/container/CreateAlertRule/defaults.ts b/frontend/src/container/CreateAlertRule/defaults.ts index adc7c9154d..2ac2f3a7b8 100644 --- a/frontend/src/container/CreateAlertRule/defaults.ts +++ b/frontend/src/container/CreateAlertRule/defaults.ts @@ -40,6 +40,7 @@ export const alertDefaults: AlertDef = { }, queryType: EQueryType.QUERY_BUILDER, panelType: PANEL_TYPES.TIME_SERIES, + unit: undefined, }, op: defaultCompareOp, matchType: defaultMatchType, @@ -69,6 +70,7 @@ export const logAlertDefaults: AlertDef = { }, queryType: EQueryType.QUERY_BUILDER, panelType: PANEL_TYPES.TIME_SERIES, + unit: undefined, }, op: defaultCompareOp, matchType: '4', @@ -99,6 +101,7 @@ export const traceAlertDefaults: AlertDef = { }, queryType: EQueryType.QUERY_BUILDER, panelType: PANEL_TYPES.TIME_SERIES, + unit: undefined, }, op: defaultCompareOp, matchType: '4', @@ -129,6 +132,7 @@ export const exceptionAlertDefaults: AlertDef = { }, queryType: EQueryType.QUERY_BUILDER, panelType: PANEL_TYPES.TIME_SERIES, + unit: undefined, }, op: defaultCompareOp, matchType: '4', diff --git a/frontend/src/container/FormAlertRules/ChartPreview/config.ts b/frontend/src/container/FormAlertRules/ChartPreview/config.ts new file mode 100644 index 0000000000..94001bbd8c --- /dev/null +++ b/frontend/src/container/FormAlertRules/ChartPreview/config.ts @@ -0,0 +1,98 @@ +import { + DataFormats, + DataRateFormats, + MiscellaneousFormats, + ThroughputFormats, + TimeFormats, +} from 'container/NewWidget/RightContainer/types'; + +export const dataFormatConfig: Record = { + [DataFormats.BytesIEC]: 1, + [DataFormats.BytesSI]: 1, + [DataFormats.BitsIEC]: 1 / 8, + [DataFormats.BitsSI]: 1 / 8, + [DataFormats.KibiBytes]: 1024, + [DataFormats.KiloBytes]: 1000, + [DataFormats.MebiBytes]: 1024 ** 2, + [DataFormats.MegaBytes]: 1000 ** 2, + [DataFormats.GibiBytes]: 1024 ** 3, + [DataFormats.GigaBytes]: 1000 ** 3, + [DataFormats.TebiBytes]: 1024 ** 4, + [DataFormats.TeraBytes]: 1000 ** 4, + [DataFormats.PebiBytes]: 1024 ** 5, + [DataFormats.PetaBytes]: 1000 ** 5, +}; + +export const throughputConfig: Record = { + [ThroughputFormats.CountsPerSec]: 1, + [ThroughputFormats.OpsPerSec]: 1, + [ThroughputFormats.RequestsPerSec]: 1, + [ThroughputFormats.ReadsPerSec]: 1, + [ThroughputFormats.WritesPerSec]: 1, + [ThroughputFormats.IOOpsPerSec]: 1, + [ThroughputFormats.CountsPerMin]: 1 / 60, + [ThroughputFormats.OpsPerMin]: 1 / 60, + [ThroughputFormats.ReadsPerMin]: 1 / 60, + [ThroughputFormats.WritesPerMin]: 1 / 60, +}; + +export const timeUnitsConfig: Record = { + [TimeFormats.Hertz]: 1, + [TimeFormats.Nanoseconds]: 1e-9, + [TimeFormats.Microseconds]: 1e-6, + [TimeFormats.Milliseconds]: 1e-3, + [TimeFormats.Seconds]: 1, + [TimeFormats.Minutes]: 60, + [TimeFormats.Hours]: 3600, + [TimeFormats.Days]: 86400, + [TimeFormats.DurationMs]: 1e-3, + [TimeFormats.DurationS]: 1, + [TimeFormats.DurationHms]: 3600, + [TimeFormats.DurationDhms]: 86400, + [TimeFormats.Timeticks]: 1e-3, + [TimeFormats.ClockMs]: 1e-3, + [TimeFormats.ClockS]: 1, +}; + +export const dataRateUnitsConfig: Record = { + [DataRateFormats.PacketsPerSec]: 1, + [DataRateFormats.BytesPerSecIEC]: dataFormatConfig[DataFormats.BytesIEC], + [DataRateFormats.BytesPerSecSI]: dataFormatConfig[DataFormats.BytesSI], + [DataRateFormats.BitsPerSecIEC]: dataFormatConfig[DataFormats.BitsIEC], + [DataRateFormats.BitsPerSecSI]: dataFormatConfig[DataFormats.BitsSI], + [DataRateFormats.KibiBytesPerSec]: dataFormatConfig[DataFormats.KibiBytes], + [DataRateFormats.KibiBitsPerSec]: dataFormatConfig[DataFormats.KibiBytes] * 8, + [DataRateFormats.KiloBytesPerSec]: dataFormatConfig[DataFormats.KiloBytes], + [DataRateFormats.KiloBitsPerSec]: dataFormatConfig[DataFormats.KiloBytes] * 8, + [DataRateFormats.MebiBytesPerSec]: dataFormatConfig[DataFormats.MebiBytes], + [DataRateFormats.MebiBitsPerSec]: dataFormatConfig[DataFormats.MebiBytes] * 8, + [DataRateFormats.MegaBytesPerSec]: dataFormatConfig[DataFormats.MegaBytes], + [DataRateFormats.MegaBitsPerSec]: dataFormatConfig[DataFormats.MegaBytes] * 8, + [DataRateFormats.GibiBytesPerSec]: dataFormatConfig[DataFormats.GibiBytes], + [DataRateFormats.GibiBitsPerSec]: dataFormatConfig[DataFormats.GibiBytes] * 8, + [DataRateFormats.GigaBytesPerSec]: dataFormatConfig[DataFormats.GigaBytes], + [DataRateFormats.GigaBitsPerSec]: dataFormatConfig[DataFormats.GigaBytes] * 8, + [DataRateFormats.TebiBytesPerSec]: dataFormatConfig[DataFormats.TebiBytes], + [DataRateFormats.TebiBitsPerSec]: dataFormatConfig[DataFormats.TebiBytes] * 8, + [DataRateFormats.TeraBytesPerSec]: dataFormatConfig[DataFormats.TeraBytes], + [DataRateFormats.TeraBitsPerSec]: dataFormatConfig[DataFormats.TeraBytes] * 8, + [DataRateFormats.PebiBytesPerSec]: dataFormatConfig[DataFormats.PebiBytes], + [DataRateFormats.PebiBitsPerSec]: dataFormatConfig[DataFormats.PebiBytes] * 8, + [DataRateFormats.PetaBytesPerSec]: dataFormatConfig[DataFormats.PetaBytes], + [DataRateFormats.PetaBitsPerSec]: dataFormatConfig[DataFormats.PetaBytes] * 8, +}; + +export const miscUnitsConfig: Record = { + [MiscellaneousFormats.None]: 1, + [MiscellaneousFormats.String]: 1, + [MiscellaneousFormats.Short]: 1, + [MiscellaneousFormats.Percent]: 0.01, + [MiscellaneousFormats.PercentUnit]: 1, + [MiscellaneousFormats.Humidity]: 1, + [MiscellaneousFormats.Decibel]: 1, + [MiscellaneousFormats.Hexadecimal0x]: 1, + [MiscellaneousFormats.Hexadecimal]: 1, + [MiscellaneousFormats.ScientificNotation]: 1, + [MiscellaneousFormats.LocaleFormat]: 1, + [MiscellaneousFormats.Pixels]: 1, +}; diff --git a/frontend/src/container/FormAlertRules/ChartPreview/index.tsx b/frontend/src/container/FormAlertRules/ChartPreview/index.tsx index 33bcfa3c37..f6bf35cbd7 100644 --- a/frontend/src/container/FormAlertRules/ChartPreview/index.tsx +++ b/frontend/src/container/FormAlertRules/ChartPreview/index.tsx @@ -9,10 +9,12 @@ import { useGetQueryRange } from 'hooks/queryBuilder/useGetQueryRange'; import getChartData from 'lib/getChartData'; import { useMemo } from 'react'; import { useTranslation } from 'react-i18next'; +import { AlertDef } from 'types/api/alerts/def'; import { Query } from 'types/api/queryBuilder/queryBuilderData'; import { EQueryType } from 'types/common/dashboard'; import { ChartContainer, FailedMessageContainer } from './styles'; +import { covertIntoDataFormats } from './utils'; export interface ChartPreviewProps { name: string; @@ -21,7 +23,7 @@ export interface ChartPreviewProps { selectedTime?: timePreferenceType; selectedInterval?: Time; headline?: JSX.Element; - threshold?: number | undefined; + alertDef?: AlertDef; userQueryKey?: string; } @@ -32,18 +34,28 @@ function ChartPreview({ selectedTime = 'GLOBAL_TIME', selectedInterval = '5min', headline, - threshold, userQueryKey, + alertDef, }: ChartPreviewProps): JSX.Element | null { const { t } = useTranslation('alerts'); + const threshold = alertDef?.condition.target || 0; + + const thresholdValue = covertIntoDataFormats({ + value: threshold, + sourceUnit: alertDef?.condition.targetUnit, + targetUnit: query?.unit, + }); + const staticLine: StaticLineProps | undefined = threshold !== undefined ? { - yMin: threshold, - yMax: threshold, + yMin: thresholdValue, + yMax: thresholdValue, borderColor: '#f14', borderWidth: 1, - lineText: `${t('preview_chart_threshold_label')} (y=${threshold})`, + lineText: `${t('preview_chart_threshold_label')} (y=${thresholdValue} ${ + query?.unit || '' + })`, textColor: '#f14', } : undefined; @@ -121,6 +133,7 @@ function ChartPreview({ staticLine={staticLine} panelData={queryResponse.data?.payload.data.newResult.data.result || []} query={query || initialQueriesMap.metrics} + yAxisUnit={query?.unit} /> )} @@ -132,8 +145,8 @@ ChartPreview.defaultProps = { selectedTime: 'GLOBAL_TIME', selectedInterval: '5min', headline: undefined, - threshold: undefined, userQueryKey: '', + alertDef: undefined, }; export default ChartPreview; diff --git a/frontend/src/container/FormAlertRules/ChartPreview/utils.test.ts b/frontend/src/container/FormAlertRules/ChartPreview/utils.test.ts new file mode 100644 index 0000000000..e81b57b933 --- /dev/null +++ b/frontend/src/container/FormAlertRules/ChartPreview/utils.test.ts @@ -0,0 +1,105 @@ +import { DataFormats } from 'container/NewWidget/RightContainer/types'; + +import { covertIntoDataFormats } from './utils'; + +describe('Convert One Unit to another unit', () => { + it('should convert from BitsIEC to BytesIEC', () => { + const result = covertIntoDataFormats({ + value: 8, + sourceUnit: DataFormats.BitsIEC, + targetUnit: DataFormats.BytesIEC, + }); + expect(result).toBe(1); + }); + + // for KibiBytes to MebiBytes conversion + it('should convert from KibiBytes to MebiBytes', () => { + const result = covertIntoDataFormats({ + value: 1024, + sourceUnit: DataFormats.KibiBytes, + targetUnit: DataFormats.MebiBytes, + }); + expect(result).toBe(1); + }); + + // for MegaBytes to GigaBytes conversion (SI units) + it('should convert from MegaBytes to GigaBytes (SI)', () => { + const result = covertIntoDataFormats({ + value: 1000, + sourceUnit: DataFormats.MegaBytes, + targetUnit: DataFormats.GigaBytes, + }); + expect(result).toBe(1); + }); + + // for identity conversion + it('should handle identity conversion', () => { + const result = covertIntoDataFormats({ + value: 100, + sourceUnit: DataFormats.KibiBytes, + targetUnit: DataFormats.KibiBytes, + }); + expect(result).toBe(100); + }); + + // BytesIEC to BitsIEC conversion + it('should convert from BytesIEC to BitsIEC', () => { + const result = covertIntoDataFormats({ + value: 1, + sourceUnit: DataFormats.BytesIEC, + targetUnit: DataFormats.BitsIEC, + }); + expect(result).toBe(8); + }); + + // for GibiBytes to TebiBytes conversion + it('should convert from GibiBytes to TebiBytes', () => { + const result = covertIntoDataFormats({ + value: 1024, + sourceUnit: DataFormats.GibiBytes, + targetUnit: DataFormats.TebiBytes, + }); + expect(result).toBe(1); + }); + + // for GigaBytes to TeraBytes conversion (SI units) + it('should convert from GigaBytes to TeraBytes (SI)', () => { + const result = covertIntoDataFormats({ + value: 1000, + sourceUnit: DataFormats.GigaBytes, + targetUnit: DataFormats.TeraBytes, + }); + expect(result).toBe(1); + }); + + // for GigaBytes to GibiBytes conversion (cross conversion) + it('should convert from GigaBytes to GibiBytes', () => { + const result = covertIntoDataFormats({ + value: 1, + sourceUnit: DataFormats.GigaBytes, + targetUnit: DataFormats.GibiBytes, + }); + // 1 GB = 0.93132257461548 GiB approximately + expect(result).toBeCloseTo(0.93132257461548); + }); + + // for a large number conversion + it('should handle large number conversion from PebiBytes to BitsIEC', () => { + const result = covertIntoDataFormats({ + value: 1, + sourceUnit: DataFormats.PebiBytes, + targetUnit: DataFormats.BitsIEC, + }); + expect(result).toBe(1 * 1024 ** 5 * 8); // 1 PebiByte = 2^50 Bytes = 2^53 Bits + }); + + // Negative value conversion + it('should handle negative values', () => { + const result = covertIntoDataFormats({ + value: -1, + sourceUnit: DataFormats.KibiBytes, + targetUnit: DataFormats.BytesIEC, + }); + expect(result).toBe(-1024); + }); +}); diff --git a/frontend/src/container/FormAlertRules/ChartPreview/utils.ts b/frontend/src/container/FormAlertRules/ChartPreview/utils.ts new file mode 100644 index 0000000000..0dbcc21603 --- /dev/null +++ b/frontend/src/container/FormAlertRules/ChartPreview/utils.ts @@ -0,0 +1,54 @@ +import { + BooleanFormats, + DataFormats, + DataRateFormats, + MiscellaneousFormats, + ThroughputFormats, + TimeFormats, +} from 'container/NewWidget/RightContainer/types'; + +import { + dataFormatConfig, + dataRateUnitsConfig, + miscUnitsConfig, + throughputConfig, + timeUnitsConfig, +} from './config'; + +export function covertIntoDataFormats({ + value, + sourceUnit, + targetUnit, +}: IUnit): number { + if (Object.values(BooleanFormats).includes(sourceUnit as BooleanFormats)) { + return 1; + } + + const sourceMultiplier = + dataFormatConfig[sourceUnit as DataFormats] || + timeUnitsConfig[sourceUnit as TimeFormats] || + dataRateUnitsConfig[sourceUnit as DataRateFormats] || + miscUnitsConfig[sourceUnit as MiscellaneousFormats] || + throughputConfig[sourceUnit as ThroughputFormats]; + + const targetDivider = + dataFormatConfig[targetUnit as DataFormats] || + timeUnitsConfig[targetUnit as TimeFormats] || + dataRateUnitsConfig[targetUnit as DataRateFormats] || + miscUnitsConfig[targetUnit as MiscellaneousFormats] || + throughputConfig[sourceUnit as ThroughputFormats]; + + const intermediateValue = value * sourceMultiplier; + + const roundedValue = Math.round(intermediateValue * 1000000) / 1000000; + + const result = roundedValue / targetDivider; + + return Number.isNaN(result) ? 0 : result; +} + +interface IUnit { + value: number; + sourceUnit?: string; + targetUnit?: string; +} diff --git a/frontend/src/container/FormAlertRules/RuleOptions.tsx b/frontend/src/container/FormAlertRules/RuleOptions.tsx index 22238a941b..8ece1562fe 100644 --- a/frontend/src/container/FormAlertRules/RuleOptions.tsx +++ b/frontend/src/container/FormAlertRules/RuleOptions.tsx @@ -1,4 +1,17 @@ -import { Form, InputNumber, InputNumberProps, Select, Typography } from 'antd'; +import { + Form, + InputNumber, + InputNumberProps, + Select, + SelectProps, + Space, + Typography, +} from 'antd'; +import { + getCategoryByOptionId, + getCategorySelectOptionByName, +} from 'container/NewWidget/RightContainer/alertFomatCategories'; +import { useQueryBuilder } from 'hooks/queryBuilder/useQueryBuilder'; import { useTranslation } from 'react-i18next'; import { AlertDef, @@ -10,9 +23,6 @@ import { EQueryType } from 'types/common/dashboard'; import { FormContainer, InlineSelect, StepHeading } from './styles'; -const { Option } = Select; -const FormItem = Form.Item; - function RuleOptions({ alertDef, setAlertDef, @@ -20,6 +30,7 @@ function RuleOptions({ }: RuleOptionsProps): JSX.Element { // init namespace for translations const { t } = useTranslation('alerts'); + const { currentQuery } = useQueryBuilder(); const handleMatchOptChange = (value: string | unknown): void => { const m = (value as string) || alertDef.condition?.matchType; @@ -49,10 +60,10 @@ function RuleOptions({ }); }} > - - - - + {t('option_above')} + {t('option_below')} + {t('option_equal')} + {t('option_notequal')} ); @@ -63,10 +74,10 @@ function RuleOptions({ value={alertDef.condition?.matchType} onChange={(value: string | unknown): void => handleMatchOptChange(value)} > - - - - + {t('option_atleastonce')} + {t('option_allthetimes')} + {t('option_onaverage')} + {t('option_intotal')} ); @@ -77,7 +88,7 @@ function RuleOptions({ value={alertDef.condition?.matchType} onChange={(value: string | unknown): void => handleMatchOptChange(value)} > - + {t('option_atleastonce')} ); @@ -94,31 +105,30 @@ function RuleOptions({ }); }} > - {' '} - - - - - - + {t('option_5min')} + {t('option_10min')} + {t('option_15min')} + {t('option_60min')} + {t('option_4hours')} + {t('option_24hours')} ); const renderThresholdRuleOpts = (): JSX.Element => ( - + {t('text_condition1')} {renderCompareOps()} {t('text_condition2')}{' '} {renderThresholdMatchOpts()} {t('text_condition3')} {renderEvalWindows()} - + ); const renderPromRuleOptions = (): JSX.Element => ( - + {t('text_condition1')} {renderCompareOps()} {t('text_condition2')}{' '} {renderPromMatchOpts()} - + ); const onChange: InputNumberProps['onChange'] = (value): void => { @@ -133,6 +143,22 @@ function RuleOptions({ }); }; + const onChangeAlertUnit: SelectProps['onChange'] = (value) => { + setAlertDef({ + ...alertDef, + condition: { + ...alertDef.condition, + targetUnit: value as string, + }, + }); + }; + + const selectedCategory = getCategoryByOptionId(currentQuery?.unit || ''); + + const categorySelectOptions = getCategorySelectOptionByName( + selectedCategory?.name, + ); + return ( <> {t('alert_form_step2')} @@ -140,14 +166,29 @@ function RuleOptions({ {queryCategory === EQueryType.PROM ? renderPromRuleOptions() : renderThresholdRuleOpts()} - - - + + + + e.currentTarget.blur()} + /> + + + + + + ); +} + +export { BuilderUnitsFilter }; diff --git a/frontend/src/container/QueryBuilder/filters/BuilderUnitsFilter/config.ts b/frontend/src/container/QueryBuilder/filters/BuilderUnitsFilter/config.ts new file mode 100644 index 0000000000..244591c2c2 --- /dev/null +++ b/frontend/src/container/QueryBuilder/filters/BuilderUnitsFilter/config.ts @@ -0,0 +1,10 @@ +import { CategoryNames } from 'container/NewWidget/RightContainer/types'; + +export const categoryToSupport = [ + CategoryNames.Data, + CategoryNames.DataRate, + CategoryNames.Time, + CategoryNames.Throughput, + CategoryNames.Miscellaneous, + CategoryNames.Boolean, +]; diff --git a/frontend/src/container/QueryBuilder/filters/BuilderUnitsFilter/index.ts b/frontend/src/container/QueryBuilder/filters/BuilderUnitsFilter/index.ts new file mode 100644 index 0000000000..977a301ca7 --- /dev/null +++ b/frontend/src/container/QueryBuilder/filters/BuilderUnitsFilter/index.ts @@ -0,0 +1 @@ +export { BuilderUnitsFilter } from './BuilderUnits'; diff --git a/frontend/src/container/QueryBuilder/filters/BuilderUnitsFilter/styles.ts b/frontend/src/container/QueryBuilder/filters/BuilderUnitsFilter/styles.ts new file mode 100644 index 0000000000..ddfba28930 --- /dev/null +++ b/frontend/src/container/QueryBuilder/filters/BuilderUnitsFilter/styles.ts @@ -0,0 +1,11 @@ +import styled from 'styled-components'; + +export const selectStyles: React.CSSProperties = { + minWidth: '10rem', +}; + +export const DefaultLabel = styled.label` + display: inline-block; + font-size: 1rem; + line-height: 2rem; +`; diff --git a/frontend/src/container/QueryBuilder/filters/BuilderUnitsFilter/types.ts b/frontend/src/container/QueryBuilder/filters/BuilderUnitsFilter/types.ts new file mode 100644 index 0000000000..693dab7be6 --- /dev/null +++ b/frontend/src/container/QueryBuilder/filters/BuilderUnitsFilter/types.ts @@ -0,0 +1,3 @@ +export interface IBuilderUnitsFilterProps { + onChange?: (value: string) => void; +} diff --git a/frontend/src/container/QueryBuilder/filters/BuilderUnitsFilter/utils.ts b/frontend/src/container/QueryBuilder/filters/BuilderUnitsFilter/utils.ts new file mode 100644 index 0000000000..a3a2947608 --- /dev/null +++ b/frontend/src/container/QueryBuilder/filters/BuilderUnitsFilter/utils.ts @@ -0,0 +1,6 @@ +import { DefaultOptionType } from 'antd/es/select'; + +export const filterOption = ( + inputValue: string, + option: DefaultOptionType['options'][number], +): boolean => option.label.toLowerCase().includes(inputValue.toLowerCase()); diff --git a/frontend/src/container/QueryBuilder/filters/index.ts b/frontend/src/container/QueryBuilder/filters/index.ts index d15a242fde..5a7292e5b1 100644 --- a/frontend/src/container/QueryBuilder/filters/index.ts +++ b/frontend/src/container/QueryBuilder/filters/index.ts @@ -1,4 +1,5 @@ export { AggregatorFilter } from './AggregatorFilter'; +export { BuilderUnitsFilter } from './BuilderUnitsFilter'; export { GroupByFilter } from './GroupByFilter'; export { HavingFilter } from './HavingFilter'; export { OperatorsSelect } from './OperatorsSelect'; diff --git a/frontend/src/lib/newQueryBuilder/queryBuilderMappers/mapQueryDataFromApi.ts b/frontend/src/lib/newQueryBuilder/queryBuilderMappers/mapQueryDataFromApi.ts index f30bfc13b7..733513b33b 100644 --- a/frontend/src/lib/newQueryBuilder/queryBuilderMappers/mapQueryDataFromApi.ts +++ b/frontend/src/lib/newQueryBuilder/queryBuilderMappers/mapQueryDataFromApi.ts @@ -33,5 +33,6 @@ export const mapQueryDataFromApi = ( clickhouse_sql: clickhouseSql, queryType: compositeQuery.queryType, id: uuid(), + unit: compositeQuery.unit, }; }; diff --git a/frontend/src/providers/QueryBuilder.tsx b/frontend/src/providers/QueryBuilder.tsx index 4de8de7d4a..7c1f1d9792 100644 --- a/frontend/src/providers/QueryBuilder.tsx +++ b/frontend/src/providers/QueryBuilder.tsx @@ -71,6 +71,7 @@ export const QueryBuilderContext = createContext({ updateAllQueriesOperators: () => initialQueriesMap.metrics, updateQueriesData: () => initialQueriesMap.metrics, initQueryBuilderData: () => {}, + handleOnUnitsChange: () => {}, }); export function QueryBuilderProvider({ @@ -176,6 +177,7 @@ export function QueryBuilderProvider({ queryData: setupedQueryData, }, id: query.id, + unit: query.unit, }; const nextQuery: Query = { @@ -474,6 +476,7 @@ export function QueryBuilderProvider({ promql, clickhouse_sql: clickhouseSql, id: uuid(), + unit: query.unit || initialQueryState.unit, }; urlQuery.set( @@ -513,6 +516,7 @@ export function QueryBuilderProvider({ promql: currentQuery.promql, id: currentQuery.id, queryType, + unit: currentQuery.unit, }, maxTime, minTime, @@ -550,6 +554,16 @@ export function QueryBuilderProvider({ stagedQuery, ]); + const handleOnUnitsChange = useCallback( + (unit: string) => { + setCurrentQuery((prevState) => ({ + ...prevState, + unit, + })); + }, + [setCurrentQuery], + ); + const query: Query = useMemo( () => ({ ...currentQuery, @@ -585,6 +599,7 @@ export function QueryBuilderProvider({ updateAllQueriesOperators, updateQueriesData, initQueryBuilderData, + handleOnUnitsChange, }), [ query, @@ -607,6 +622,7 @@ export function QueryBuilderProvider({ updateAllQueriesOperators, updateQueriesData, initQueryBuilderData, + handleOnUnitsChange, ], ); diff --git a/frontend/src/store/actions/dashboard/getQueryResults.ts b/frontend/src/store/actions/dashboard/getQueryResults.ts index 1487b3f7c8..a132fc8e78 100644 --- a/frontend/src/store/actions/dashboard/getQueryResults.ts +++ b/frontend/src/store/actions/dashboard/getQueryResults.ts @@ -34,6 +34,7 @@ export async function GetMetricQueryRange({ compositeQuery: { queryType: query.queryType, panelType: graphType, + unit: query?.unit, }, }; diff --git a/frontend/src/types/api/alerts/compositeQuery.ts b/frontend/src/types/api/alerts/compositeQuery.ts index 1f25718367..f2856fbb3d 100644 --- a/frontend/src/types/api/alerts/compositeQuery.ts +++ b/frontend/src/types/api/alerts/compositeQuery.ts @@ -3,6 +3,7 @@ import { BuilderClickHouseResource, BuilderPromQLResource, BuilderQueryDataResourse, + Query, } from 'types/api/queryBuilder/queryBuilderData'; import { EQueryType } from 'types/common/dashboard'; @@ -12,4 +13,5 @@ export interface ICompositeMetricQuery { chQueries: BuilderClickHouseResource; queryType: EQueryType; panelType: PANEL_TYPES; + unit: Query['unit']; } diff --git a/frontend/src/types/api/alerts/def.ts b/frontend/src/types/api/alerts/def.ts index 8d5440e7d9..704a05765e 100644 --- a/frontend/src/types/api/alerts/def.ts +++ b/frontend/src/types/api/alerts/def.ts @@ -28,6 +28,7 @@ export interface RuleCondition { op?: string | undefined; target?: number | undefined; matchType?: string | undefined; + targetUnit?: string | undefined; } export interface Labels { diff --git a/frontend/src/types/api/queryBuilder/queryBuilderData.ts b/frontend/src/types/api/queryBuilder/queryBuilderData.ts index b16aac3b3c..926785e072 100644 --- a/frontend/src/types/api/queryBuilder/queryBuilderData.ts +++ b/frontend/src/types/api/queryBuilder/queryBuilderData.ts @@ -1,3 +1,4 @@ +import { Format } from 'container/NewWidget/RightContainer/types'; import { EQueryType } from 'types/common/dashboard'; import { DataSource, @@ -82,6 +83,7 @@ export interface Query { builder: QueryBuilderData; clickhouse_sql: IClickHouseQuery[]; id: string; + unit?: Format['id']; } export type QueryState = Omit; diff --git a/frontend/src/types/common/queryBuilder.ts b/frontend/src/types/common/queryBuilder.ts index 5e7cf57b02..3d74f30fdc 100644 --- a/frontend/src/types/common/queryBuilder.ts +++ b/frontend/src/types/common/queryBuilder.ts @@ -1,4 +1,5 @@ import { PANEL_TYPES } from 'constants/queryBuilder'; +import { Format } from 'container/NewWidget/RightContainer/types'; import { IBuilderFormula, IBuilderQuery, @@ -187,6 +188,7 @@ export type QueryBuilderContextType = { ) => void; handleRunQuery: () => void; resetStagedQuery: () => void; + handleOnUnitsChange: (units: Format['id']) => void; updateAllQueriesOperators: ( queryData: Query, panelType: PANEL_TYPES,