You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

180 lines
6.9 KiB

# 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