SeriesVisibilityConfigFactory.ts 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171
  1. import {
  2. ByNamesMatcherMode,
  3. DataFrame,
  4. DynamicConfigValue,
  5. FieldConfigSource,
  6. FieldMatcherID,
  7. FieldType,
  8. getFieldDisplayName,
  9. isSystemOverrideWithRef,
  10. SystemConfigOverrideRule,
  11. } from '@grafana/data';
  12. import { SeriesVisibilityChangeMode } from '@grafana/ui';
  13. const displayOverrideRef = 'hideSeriesFrom';
  14. const isHideSeriesOverride = isSystemOverrideWithRef(displayOverrideRef);
  15. export function seriesVisibilityConfigFactory(
  16. label: string,
  17. mode: SeriesVisibilityChangeMode,
  18. fieldConfig: FieldConfigSource,
  19. data: DataFrame[]
  20. ) {
  21. const { overrides } = fieldConfig;
  22. const displayName = label;
  23. const currentIndex = overrides.findIndex(isHideSeriesOverride);
  24. if (currentIndex < 0) {
  25. if (mode === SeriesVisibilityChangeMode.ToggleSelection) {
  26. const override = createOverride([displayName]);
  27. return {
  28. ...fieldConfig,
  29. overrides: [...fieldConfig.overrides, override],
  30. };
  31. }
  32. const displayNames = getDisplayNames(data, displayName);
  33. const override = createOverride(displayNames);
  34. return {
  35. ...fieldConfig,
  36. overrides: [...fieldConfig.overrides, override],
  37. };
  38. }
  39. const overridesCopy = Array.from(overrides);
  40. const [current] = overridesCopy.splice(currentIndex, 1) as SystemConfigOverrideRule[];
  41. if (mode === SeriesVisibilityChangeMode.ToggleSelection) {
  42. const existing = getExistingDisplayNames(current);
  43. if (existing[0] === displayName && existing.length === 1) {
  44. return {
  45. ...fieldConfig,
  46. overrides: overridesCopy,
  47. };
  48. }
  49. const override = createOverride([displayName]);
  50. return {
  51. ...fieldConfig,
  52. overrides: [...overridesCopy, override],
  53. };
  54. }
  55. const override = createExtendedOverride(current, displayName);
  56. if (allFieldsAreExcluded(override, data)) {
  57. return {
  58. ...fieldConfig,
  59. overrides: overridesCopy,
  60. };
  61. }
  62. return {
  63. ...fieldConfig,
  64. overrides: [...overridesCopy, override],
  65. };
  66. }
  67. function createOverride(
  68. names: string[],
  69. mode = ByNamesMatcherMode.exclude,
  70. property?: DynamicConfigValue
  71. ): SystemConfigOverrideRule {
  72. property = property ?? {
  73. id: 'custom.hideFrom',
  74. value: {
  75. viz: true,
  76. legend: false,
  77. tooltip: false,
  78. },
  79. };
  80. return {
  81. __systemRef: displayOverrideRef,
  82. matcher: {
  83. id: FieldMatcherID.byNames,
  84. options: {
  85. mode: mode,
  86. names: names,
  87. prefix: mode === ByNamesMatcherMode.exclude ? 'All except:' : undefined,
  88. readOnly: true,
  89. },
  90. },
  91. properties: [
  92. {
  93. ...property,
  94. value: {
  95. viz: true,
  96. legend: false,
  97. tooltip: false,
  98. },
  99. },
  100. ],
  101. };
  102. }
  103. const createExtendedOverride = (
  104. current: SystemConfigOverrideRule,
  105. displayName: string,
  106. mode = ByNamesMatcherMode.exclude
  107. ): SystemConfigOverrideRule => {
  108. const property = current.properties.find((p) => p.id === 'custom.hideFrom');
  109. const existing = getExistingDisplayNames(current);
  110. const index = existing.findIndex((name) => name === displayName);
  111. if (index < 0) {
  112. existing.push(displayName);
  113. } else {
  114. existing.splice(index, 1);
  115. }
  116. return createOverride(existing, mode, property);
  117. };
  118. const getExistingDisplayNames = (rule: SystemConfigOverrideRule): string[] => {
  119. const names = rule.matcher.options?.names;
  120. if (!Array.isArray(names)) {
  121. return [];
  122. }
  123. return [...names];
  124. };
  125. const allFieldsAreExcluded = (override: SystemConfigOverrideRule, data: DataFrame[]): boolean => {
  126. return getExistingDisplayNames(override).length === getDisplayNames(data).length;
  127. };
  128. const getDisplayNames = (data: DataFrame[], excludeName?: string): string[] => {
  129. const unique = new Set<string>();
  130. for (const frame of data) {
  131. for (const field of frame.fields) {
  132. if (field.type !== FieldType.number) {
  133. continue;
  134. }
  135. const name = getFieldDisplayName(field, frame, data);
  136. if (name === excludeName) {
  137. continue;
  138. }
  139. unique.add(name);
  140. }
  141. }
  142. return Array.from(unique);
  143. };