# Copyright (C) 2005-2025 Splunk Inc. All Rights Reserved. from ..utils import get_nested def is_kpi(item): asset_id = get_nested(item, ['statModel', 'assetId']) if not asset_id: # Rectangle/Ellipse/Icon widgets do not have an assetId in statModel, so use the one outside of statModel asset_id = item.get('assetId') return asset_id or (item.get('parent') and item.get('parent') != 'null') def transform_thresholds_singlevalue(item): if is_kpi(item): return { 'options': { 'sparklineValues': '> primary | seriesByName("alert_value")', 'backgroundColor': '> primary | seriesByName("alert_color") | lastPoint()', 'majorColor': '#FFFFFF' } } else: # this is ad hoc: process the threshold field and ranges data is_thresholding_enabled = get_nested(item, ['statModel', 'thresholdMode']) threshold_levels = get_nested(item, ['statModel', 'thresholdSettingModel', 'thresholdLevels']) base_color = get_nested(item, ['statModel', 'thresholdSettingModel', 'baseSeverityColor']) severity_color = get_nested(item, ['statModel', 'severityColor']) if is_thresholding_enabled and threshold_levels: ranges = convert_ranges(base_color, threshold_levels) return { 'options': { 'backgroundColor': '> majorValue | rangeValue(backgroundColorEditorConfig)', 'majorColor': '#FFFFFF' }, 'context': { 'backgroundColorEditorConfig': ranges } } # thresholding is on, but no levels defined or thresholding is off return { 'options': { 'backgroundColor': base_color or severity_color, 'majorColor': '#FFFFFF' } } def transform_thresholds_singlevalueicon(item): if is_kpi(item): return { 'options': { 'iconColor': '> primary | seriesByName("alert_color") | lastPoint()' } } else: # this is ad hoc: process the threshold field and ranges data is_thresholding_enabled = get_nested(item, ['statModel', 'thresholdMode']) threshold_levels = get_nested(item, ['statModel', 'thresholdSettingModel', 'thresholdLevels']) base_color = get_nested(item, ['statModel', 'thresholdSettingModel', 'baseSeverityColor']) severity_color = get_nested(item, ['statModel', 'severityColor']) if threshold_levels and is_thresholding_enabled: ranges = convert_ranges(base_color, threshold_levels) return { 'options': { 'iconColor': '> majorValue | rangeValue(iconColorEditorConfig)' }, 'context': { 'iconColorEditorConfig': ranges } } # thresholding is on, but no levels defined or thresholding is off return { 'options': { 'backgroundColor': base_color or severity_color } } def transform_thresholds_deprecated(item): """ Goes over threshold settings in item and returns converted options dict to merge with UDF viz item This logic should be common for both ad hoc and KPI searches. Only copies over threshold settings if thresholds are turned on for the converted Widget :return: Object for merging with UDF widget viz options """ if is_kpi(item): return { 'encoding': { 'trend': 'primary.alert_value', 'fill': 'primary.alert_color' } } else: # this is an ad hoc is_thresholding_enabled = get_nested(item, ['statModel', 'thresholdMode']) threshold_levels = get_nested(item, ['statModel', 'thresholdSettingModel', 'thresholdLevels']) base_color = get_nested(item, ['statModel', 'thresholdSettingModel', 'baseSeverityColor']) severity_color = get_nested(item, ['statModel', 'severityColor']) if threshold_levels and is_thresholding_enabled: ranges = convert_ranges(base_color, threshold_levels) return { 'encoding': { 'trend': 'primary.alert_value', 'fill': { 'field': 'primary.alert_value', 'format': { 'type': 'rangevalue', 'ranges': ranges } } } } else: return { 'options': { 'backgroundColor': base_color or severity_color } } def transform_thresholds_line(item): asset_id = item.get('assetId') if asset_id: # this is KPI return { 'options': { 'strokeDataSeries': '> primary | seriesByType("color")', 'strokeDataPoint': '> strokeDataSeries | lastPoint()', 'strokeColor': '> strokeDataPoint' } } else: # this is ad hoc: process the threshold field and ranges data is_thresholding_enabled = get_nested(item, ['statModel', 'thresholdMode']) threshold_levels = get_nested(item, ['statModel', 'thresholdSettingModel', 'thresholdLevels']) base_color = get_nested(item, ['statModel', 'thresholdSettingModel', 'baseSeverityColor']) if threshold_levels and is_thresholding_enabled: ranges = convert_ranges(base_color, threshold_levels) return { 'options': { 'strokeDataSeries': '> primary | seriesByName("alert_value")', 'strokeDataPoint': '> strokeDataSeries | lastPoint()', 'strokeColor': '> strokeDataPoint | rangeValue(strokeColorEditorConfig)' }, 'context': { 'strokeColorEditorConfig': ranges } } def convert_ranges(base_color, threshold_levels): ranges = [] prevColor = base_color prevValue = 0 for level in threshold_levels: # UDF expects the number of colors to be one more than number of values: first color is base if not ranges: # For base case, we go up to the first value and set to base color ranges.append({ 'value': base_color, 'to': int(level['thresholdValue']) }) else: # Insert at beginning because UDF expects the thresholds in a specific order ranges.insert(0, { 'value': prevColor, 'to': int(level['thresholdValue']), 'from': prevValue }) prevColor = level['severityColor'] prevValue = int(level['thresholdValue']) # Add last thresholding color ranges.insert(0, { 'value': prevColor, 'from': prevValue }) return ranges