Просмотр исходного кода

feat(profiling): change color encoding options (#46034)

Change default to system vs application and rename the options to color
coding.

The motivation to change color encoding to system vs application is that
we have seen that many of our users (especially those not very familiar)
are overwhelmed by the amount of information the flamechart presents.
The amount of different colors adds to that confusion, so to alleviate
that we are changing to distinguish frames by system and application.
This also allows presents a small opportunity to educate the user on the
first concept of app vs system frames, hence the change to add
`application` | `system` into the tooltip so a quick hover action can
explain the situation.

I also made the minimap inherit the same color coding and renamed the
"options" in the top right toolbar to "Color Coding" as it was the only
option in the list anyways. The wording "Options" is also super generic
and users just skim through and never look at it.

Light theme colors
<img width="1631" alt="CleanShot 2023-03-20 at 09 33 25@2x"
src="https://user-images.githubusercontent.com/9317857/226355719-5c74308d-ad35-4dcc-a0b1-68d99e75d9fb.png">

Dark theme colors
<img width="1632" alt="CleanShot 2023-03-20 at 09 33 11@2x"
src="https://user-images.githubusercontent.com/9317857/226355759-15c743f1-9f60-40c9-ba0b-31c605cf3cec.png">

---------

Co-authored-by: Tony Xiao <txiao@sentry.io>
Jonas 2 лет назад
Родитель
Сommit
65749ea8c6

+ 3 - 2
static/app/components/profiling/flamegraph/flamegraphContextMenu.tsx

@@ -28,18 +28,19 @@ import useOrganization from 'sentry/utils/useOrganization';
 import useProjects from 'sentry/utils/useProjects';
 import useProjects from 'sentry/utils/useProjects';
 
 
 const FLAMEGRAPH_COLOR_CODINGS: FlamegraphColorCodings = [
 const FLAMEGRAPH_COLOR_CODINGS: FlamegraphColorCodings = [
-  'by symbol name',
+  'by system vs application frame',
   'by system frame',
   'by system frame',
   'by application frame',
   'by application frame',
+  'by symbol name',
   'by library',
   'by library',
   'by recursion',
   'by recursion',
   'by frequency',
   'by frequency',
 ];
 ];
 const FLAMEGRAPH_VIEW_OPTIONS: FlamegraphViewOptions[] = ['top down', 'bottom up'];
 const FLAMEGRAPH_VIEW_OPTIONS: FlamegraphViewOptions[] = ['top down', 'bottom up'];
 const FLAMEGRAPH_SORTING_OPTIONS: FlamegraphSorting[] = [
 const FLAMEGRAPH_SORTING_OPTIONS: FlamegraphSorting[] = [
+  'call order',
   'alphabetical',
   'alphabetical',
   'left heavy',
   'left heavy',
-  'call order',
 ];
 ];
 
 
 interface FlamegraphContextMenuProps {
 interface FlamegraphContextMenuProps {

+ 20 - 22
static/app/components/profiling/flamegraph/flamegraphToolbar/flamegraphOptionsMenu.tsx

@@ -1,8 +1,7 @@
-import {Fragment} from 'react';
+import {Fragment, useCallback} from 'react';
 
 
 import {Button} from 'sentry/components/button';
 import {Button} from 'sentry/components/button';
-import {SelectOption} from 'sentry/components/compactSelect';
-import {CompositeSelect} from 'sentry/components/compactSelect/composite';
+import {CompactSelect, SelectOption} from 'sentry/components/compactSelect';
 import {IconSliders} from 'sentry/icons';
 import {IconSliders} from 'sentry/icons';
 import {t} from 'sentry/locale';
 import {t} from 'sentry/locale';
 import {CanvasPoolManager} from 'sentry/utils/profiling/canvasScheduler';
 import {CanvasPoolManager} from 'sentry/utils/profiling/canvasScheduler';
@@ -20,37 +19,36 @@ function FlamegraphOptionsMenu({
   const {colorCoding} = useFlamegraphPreferences();
   const {colorCoding} = useFlamegraphPreferences();
   const dispatch = useDispatchFlamegraphState();
   const dispatch = useDispatchFlamegraphState();
 
 
+  const onColorChange = useCallback(
+    (opt: SelectOption<any>) => {
+      dispatch({
+        type: 'set color coding',
+        payload: opt.value,
+      });
+    },
+    [dispatch]
+  );
+
   return (
   return (
     <Fragment>
     <Fragment>
       <Button size="xs" onClick={() => canvasPoolManager.dispatch('reset zoom', [])}>
       <Button size="xs" onClick={() => canvasPoolManager.dispatch('reset zoom', [])}>
         {t('Reset Zoom')}
         {t('Reset Zoom')}
       </Button>
       </Button>
-      <CompositeSelect
-        triggerLabel={t('Options')}
-        triggerProps={{
-          icon: <IconSliders size="xs" />,
-          size: 'xs',
-        }}
+      <CompactSelect
+        triggerLabel={t('Color Coding')}
+        triggerProps={{icon: <IconSliders size="xs" />, size: 'xs'}}
+        options={colorCodingOptions}
         position="bottom-end"
         position="bottom-end"
+        value={colorCoding}
         closeOnSelect={false}
         closeOnSelect={false}
-      >
-        <CompositeSelect.Region
-          label={t('Color Coding')}
-          value={colorCoding}
-          options={colorCodingOptions}
-          onChange={opt =>
-            dispatch({
-              type: 'set color coding',
-              payload: opt.value,
-            })
-          }
-        />
-      </CompositeSelect>
+        onChange={onColorChange}
+      />
     </Fragment>
     </Fragment>
   );
   );
 }
 }
 
 
 const colorCodingOptions: SelectOption<FlamegraphPreferences['colorCoding']>[] = [
 const colorCodingOptions: SelectOption<FlamegraphPreferences['colorCoding']>[] = [
+  {value: 'by system vs application frame', label: t('By System vs Application Frame')},
   {value: 'by symbol name', label: t('By Symbol Name')},
   {value: 'by symbol name', label: t('By Symbol Name')},
   {value: 'by library', label: t('By Package')},
   {value: 'by library', label: t('By Package')},
   {value: 'by system frame', label: t('By System Frame')},
   {value: 'by system frame', label: t('By System Frame')},

+ 3 - 0
static/app/components/profiling/flamegraph/flamegraphTooltip.tsx

@@ -82,6 +82,9 @@ export function FlamegraphTooltip(props: FlamegraphTooltipProps) {
             {t('source')}:{formatFileNameAndLineColumn(props.frame)}
             {t('source')}:{formatFileNameAndLineColumn(props.frame)}
           </Fragment>
           </Fragment>
         )}
         )}
+        <FlamegraphTooltipTimelineInfo>
+          {props.frame.frame.is_application ? t('application frame') : t('system frame')}
+        </FlamegraphTooltipTimelineInfo>
       </FlamegraphTooltipTimelineInfo>
       </FlamegraphTooltipTimelineInfo>
       {!isCount && (
       {!isCount && (
         <FlamegraphTooltipTimelineInfo>
         <FlamegraphTooltipTimelineInfo>

+ 5 - 2
static/app/components/profiling/flamegraph/flamegraphZoomViewMinimap.tsx

@@ -8,6 +8,7 @@ import {
 } from 'sentry/utils/profiling/canvasScheduler';
 } from 'sentry/utils/profiling/canvasScheduler';
 import {CanvasView} from 'sentry/utils/profiling/canvasView';
 import {CanvasView} from 'sentry/utils/profiling/canvasView';
 import {Flamegraph} from 'sentry/utils/profiling/flamegraph';
 import {Flamegraph} from 'sentry/utils/profiling/flamegraph';
+import {useFlamegraphPreferences} from 'sentry/utils/profiling/flamegraph/hooks/useFlamegraphPreferences';
 import {useFlamegraphTheme} from 'sentry/utils/profiling/flamegraph/useFlamegraphTheme';
 import {useFlamegraphTheme} from 'sentry/utils/profiling/flamegraph/useFlamegraphTheme';
 import {FlamegraphCanvas} from 'sentry/utils/profiling/flamegraphCanvas';
 import {FlamegraphCanvas} from 'sentry/utils/profiling/flamegraphCanvas';
 import {
 import {
@@ -50,6 +51,7 @@ function FlamegraphZoomViewMinimap({
   setFlamegraphMiniMapOverlayCanvasRef,
   setFlamegraphMiniMapOverlayCanvasRef,
 }: FlamegraphZoomViewMinimapProps): React.ReactElement {
 }: FlamegraphZoomViewMinimapProps): React.ReactElement {
   const flamegraphTheme = useFlamegraphTheme();
   const flamegraphTheme = useFlamegraphTheme();
+  const {colorCoding} = useFlamegraphPreferences();
   const [lastInteraction, setLastInteraction] = useState<
   const [lastInteraction, setLastInteraction] = useState<
     'pan' | 'click' | 'zoom' | 'scroll' | 'select' | 'resize' | null
     'pan' | 'click' | 'zoom' | 'scroll' | 'select' | 'resize' | null
   >(null);
   >(null);
@@ -77,9 +79,10 @@ function FlamegraphZoomViewMinimap({
     return new FlamegraphRendererWebGL(
     return new FlamegraphRendererWebGL(
       flamegraphMiniMapCanvasRef,
       flamegraphMiniMapCanvasRef,
       flamegraph,
       flamegraph,
-      flamegraphTheme
+      flamegraphTheme,
+      {colorCoding, draw_border: false}
     );
     );
-  }, [flamegraph, flamegraphMiniMapCanvasRef, flamegraphTheme]);
+  }, [flamegraph, flamegraphMiniMapCanvasRef, colorCoding, flamegraphTheme]);
 
 
   const positionIndicatorRenderer: PositionIndicatorRenderer | null = useMemo(() => {
   const positionIndicatorRenderer: PositionIndicatorRenderer | null = useMemo(() => {
     if (!flamegraphMiniMapOverlayCanvasRef) {
     if (!flamegraphMiniMapOverlayCanvasRef) {

+ 10 - 4
static/app/utils/profiling/colors/utils.spec.tsx

@@ -6,7 +6,10 @@ import {
   makeColorMapBySymbolName,
   makeColorMapBySymbolName,
   makeStackToColor,
   makeStackToColor,
 } from 'sentry/utils/profiling/colors/utils';
 } from 'sentry/utils/profiling/colors/utils';
-import {LCH_LIGHT} from 'sentry/utils/profiling/flamegraph/flamegraphTheme';
+import {
+  LCH_LIGHT,
+  LightFlamegraphTheme,
+} from 'sentry/utils/profiling/flamegraph/flamegraphTheme';
 import {FlamegraphFrame} from 'sentry/utils/profiling/flamegraphFrame';
 import {FlamegraphFrame} from 'sentry/utils/profiling/flamegraphFrame';
 import {Frame} from 'sentry/utils/profiling/frame';
 import {Frame} from 'sentry/utils/profiling/frame';
 
 
@@ -49,7 +52,8 @@ describe('makeStackToColor', () => {
     const {colorBuffer} = makeFn(
     const {colorBuffer} = makeFn(
       frames,
       frames,
       () => new Map(),
       () => new Map(),
-      makeColorBucketTheme(LCH_LIGHT)
+      makeColorBucketTheme(LCH_LIGHT),
+      LightFlamegraphTheme
     );
     );
     expect(colorBuffer.slice(0, 4)).toEqual(fallback);
     expect(colorBuffer.slice(0, 4)).toEqual(fallback);
     expect(colorBuffer).toHaveLength(24);
     expect(colorBuffer).toHaveLength(24);
@@ -66,7 +70,8 @@ describe('makeStackToColor', () => {
     const {colorBuffer} = makeFn(
     const {colorBuffer} = makeFn(
       frames,
       frames,
       makeColorMapBySymbolName,
       makeColorMapBySymbolName,
-      makeColorBucketTheme(LCH_LIGHT)
+      makeColorBucketTheme(LCH_LIGHT),
+      LightFlamegraphTheme
     );
     );
     expect(colorBuffer.slice(0, 4)).toEqual([0.9625, 0.7125, 0.7125, 1]);
     expect(colorBuffer.slice(0, 4)).toEqual([0.9625, 0.7125, 0.7125, 1]);
     expect(
     expect(
@@ -90,7 +95,8 @@ describe('makeStackToColor', () => {
         m.set('a', [1, 0, 0]);
         m.set('a', [1, 0, 0]);
         return m;
         return m;
       },
       },
-      makeColorBucketTheme(LCH_LIGHT)
+      makeColorBucketTheme(LCH_LIGHT),
+      LightFlamegraphTheme
     );
     );
     expect(colorBuffer.slice(0, 4)).toEqual([1, 0, 0, 1]);
     expect(colorBuffer.slice(0, 4)).toEqual([1, 0, 0, 1]);
     expect(colorBuffer).toHaveLength(24);
     expect(colorBuffer).toHaveLength(24);

+ 33 - 5
static/app/utils/profiling/colors/utils.tsx

@@ -1,11 +1,11 @@
-import {SpanChart, SpanChartNode} from 'sentry/utils/profiling/spanChart';
-
 import {
 import {
   ColorChannels,
   ColorChannels,
   ColorMapFn,
   ColorMapFn,
   FlamegraphTheme,
   FlamegraphTheme,
   LCH,
   LCH,
-} from '../flamegraph/flamegraphTheme';
+} from 'sentry/utils/profiling/flamegraph/flamegraphTheme';
+import {SpanChart, SpanChartNode} from 'sentry/utils/profiling/spanChart';
+
 import {FlamegraphFrame} from '../flamegraphFrame';
 import {FlamegraphFrame} from '../flamegraphFrame';
 
 
 function uniqueCountBy<T>(
 function uniqueCountBy<T>(
@@ -86,9 +86,10 @@ export const makeStackToColor = (
   return (
   return (
     frames: ReadonlyArray<FlamegraphFrame>,
     frames: ReadonlyArray<FlamegraphFrame>,
     generateColorMap: ColorMapFn,
     generateColorMap: ColorMapFn,
-    colorBucket: FlamegraphTheme['COLORS']['COLOR_BUCKET']
+    colorBucket: FlamegraphTheme['COLORS']['COLOR_BUCKET'],
+    theme: FlamegraphTheme
   ) => {
   ) => {
-    const colorMap = generateColorMap(frames, colorBucket);
+    const colorMap = generateColorMap(frames, colorBucket, theme);
     const length = frames.length;
     const length = frames.length;
 
 
     // Length * number of frames * color components
     // Length * number of frames * color components
@@ -296,6 +297,33 @@ export function makeColorMapBySystemFrame(
   return colors;
   return colors;
 }
 }
 
 
+export function makeColorMapBySystemVsApplicationFrame(
+  frames: ReadonlyArray<FlamegraphFrame>,
+  _colorBucket: FlamegraphTheme['COLORS']['COLOR_BUCKET'],
+  theme: FlamegraphTheme
+): Map<FlamegraphFrame['frame']['key'], ColorChannels> {
+  const colors = new Map<FlamegraphFrame['key'], ColorChannels>();
+  const colorCache: Map<string, ColorChannels> = new Map();
+
+  const sortedFrames: FlamegraphFrame[] = [...frames].sort((a, b) => {
+    return (a.frame.name + a.frame.image).localeCompare(b.frame.name + b.frame.image);
+  });
+
+  for (let i = 0; i < sortedFrames.length; i++) {
+    const key = sortedFrames[i].frame.name + sortedFrames[i].frame.image;
+
+    if (sortedFrames[i].frame.is_application) {
+      colorCache.set(key, theme.COLORS.FRAME_APPLICATION_COLOR);
+    } else {
+      colorCache.set(key, theme.COLORS.FRAME_SYSTEM_COLOR);
+    }
+
+    colors.set(sortedFrames[i].key, colorCache.get(key)!);
+  }
+
+  return colors;
+}
+
 export function makeColorMapByApplicationFrame(
 export function makeColorMapByApplicationFrame(
   frames: ReadonlyArray<FlamegraphFrame>,
   frames: ReadonlyArray<FlamegraphFrame>,
   colorBucket: FlamegraphTheme['COLORS']['COLOR_BUCKET']
   colorBucket: FlamegraphTheme['COLORS']['COLOR_BUCKET']

+ 1 - 1
static/app/utils/profiling/flamegraph/flamegraphStateProvider/flamegraphContext.tsx

@@ -24,7 +24,7 @@ export const DEFAULT_FLAMEGRAPH_STATE: FlamegraphState = {
       minimap: true,
       minimap: true,
       transaction_spans: true,
       transaction_spans: true,
     },
     },
-    colorCoding: 'by symbol name',
+    colorCoding: 'by system vs application frame',
     sorting: 'call order',
     sorting: 'call order',
     view: 'top down',
     view: 'top down',
     layout: 'table bottom',
     layout: 'table bottom',

+ 2 - 1
static/app/utils/profiling/flamegraph/flamegraphStateProvider/flamegraphQueryParamSync.tsx

@@ -30,7 +30,8 @@ function isColorCoding(
     value === 'by application frame' ||
     value === 'by application frame' ||
     value === 'by library' ||
     value === 'by library' ||
     value === 'by recursion' ||
     value === 'by recursion' ||
-    value === 'by frequency'
+    value === 'by frequency' ||
+    value === 'by system vs application frame'
   );
   );
 }
 }
 
 

+ 2 - 1
static/app/utils/profiling/flamegraph/flamegraphStateProvider/reducers/flamegraphPreferences.tsx

@@ -1,9 +1,10 @@
 import {Flamegraph} from '../../../flamegraph';
 import {Flamegraph} from '../../../flamegraph';
 
 
 export type FlamegraphColorCodings = [
 export type FlamegraphColorCodings = [
-  'by symbol name',
+  'by system vs application frame',
   'by system frame',
   'by system frame',
   'by application frame',
   'by application frame',
+  'by symbol name',
   'by library',
   'by library',
   'by recursion',
   'by recursion',
   'by frequency'
   'by frequency'

+ 12 - 1
static/app/utils/profiling/flamegraph/flamegraphTheme.tsx

@@ -6,6 +6,7 @@ import {
   makeColorMapByRecursion,
   makeColorMapByRecursion,
   makeColorMapBySymbolName,
   makeColorMapBySymbolName,
   makeColorMapBySystemFrame,
   makeColorMapBySystemFrame,
+  makeColorMapBySystemVsApplicationFrame,
   makeStackToColor,
   makeStackToColor,
 } from 'sentry/utils/profiling/colors/utils';
 } from 'sentry/utils/profiling/colors/utils';
 import {FlamegraphColorCodings} from 'sentry/utils/profiling/flamegraph/flamegraphStateProvider/reducers/flamegraphPreferences';
 import {FlamegraphColorCodings} from 'sentry/utils/profiling/flamegraph/flamegraphStateProvider/reducers/flamegraphPreferences';
@@ -33,6 +34,7 @@ export type ColorChannels = [number, number, number] | [number, number, number,
 export type ColorMapFn = (
 export type ColorMapFn = (
   frames: ReadonlyArray<FlamegraphFrame>,
   frames: ReadonlyArray<FlamegraphFrame>,
   colorBucket: FlamegraphTheme['COLORS']['COLOR_BUCKET'],
   colorBucket: FlamegraphTheme['COLORS']['COLOR_BUCKET'],
+  theme: FlamegraphTheme,
   sortByKey?: (a: FlamegraphFrame, b: FlamegraphFrame) => number
   sortByKey?: (a: FlamegraphFrame, b: FlamegraphFrame) => number
 ) => Map<FlamegraphFrame['frame']['key'], ColorChannels>;
 ) => Map<FlamegraphFrame['frame']['key'], ColorChannels>;
 
 
@@ -47,7 +49,9 @@ export interface FlamegraphTheme {
     DIFFERENTIAL_DECREASE: ColorChannels;
     DIFFERENTIAL_DECREASE: ColorChannels;
     DIFFERENTIAL_INCREASE: ColorChannels;
     DIFFERENTIAL_INCREASE: ColorChannels;
     FOCUSED_FRAME_BORDER_COLOR: string;
     FOCUSED_FRAME_BORDER_COLOR: string;
+    FRAME_APPLICATION_COLOR: ColorChannels;
     FRAME_GRAYSCALE_COLOR: ColorChannels;
     FRAME_GRAYSCALE_COLOR: ColorChannels;
+    FRAME_SYSTEM_COLOR: ColorChannels;
     GRID_FRAME_BACKGROUND_COLOR: string;
     GRID_FRAME_BACKGROUND_COLOR: string;
     GRID_LINE_COLOR: string;
     GRID_LINE_COLOR: string;
     HIGHLIGHTED_LABEL_COLOR: ColorChannels;
     HIGHLIGHTED_LABEL_COLOR: ColorChannels;
@@ -68,7 +72,8 @@ export interface FlamegraphTheme {
     STACK_TO_COLOR: (
     STACK_TO_COLOR: (
       frames: ReadonlyArray<FlamegraphFrame>,
       frames: ReadonlyArray<FlamegraphFrame>,
       colorMapFn: ColorMapFn,
       colorMapFn: ColorMapFn,
-      colorBucketFn: FlamegraphTheme['COLORS']['COLOR_BUCKET']
+      colorBucketFn: FlamegraphTheme['COLORS']['COLOR_BUCKET'],
+      theme: FlamegraphTheme
     ) => {
     ) => {
       colorBuffer: Array<number>;
       colorBuffer: Array<number>;
       colorMap: Map<Frame['key'], ColorChannels>;
       colorMap: Map<Frame['key'], ColorChannels>;
@@ -173,12 +178,15 @@ export const LightFlamegraphTheme: FlamegraphTheme = {
       'by library': makeColorMapByLibrary,
       'by library': makeColorMapByLibrary,
       'by recursion': makeColorMapByRecursion,
       'by recursion': makeColorMapByRecursion,
       'by frequency': makeColorMapByFrequency,
       'by frequency': makeColorMapByFrequency,
+      'by system vs application frame': makeColorMapBySystemVsApplicationFrame,
     },
     },
     CURSOR_CROSSHAIR: '#bbbbbb',
     CURSOR_CROSSHAIR: '#bbbbbb',
     DIFFERENTIAL_DECREASE: [0.309, 0.2058, 0.98],
     DIFFERENTIAL_DECREASE: [0.309, 0.2058, 0.98],
     DIFFERENTIAL_INCREASE: [0.98, 0.2058, 0.4381],
     DIFFERENTIAL_INCREASE: [0.98, 0.2058, 0.4381],
     FOCUSED_FRAME_BORDER_COLOR: lightTheme.focus,
     FOCUSED_FRAME_BORDER_COLOR: lightTheme.focus,
     FRAME_GRAYSCALE_COLOR: [0.5, 0.5, 0.6, 0.1],
     FRAME_GRAYSCALE_COLOR: [0.5, 0.5, 0.6, 0.1],
+    FRAME_APPLICATION_COLOR: [0.1, 0.1, 0.8, 0.2],
+    FRAME_SYSTEM_COLOR: [0.7, 0.1, 0.1, 0.2],
     SPAN_FALLBACK_COLOR: [0, 0, 0, 0.1],
     SPAN_FALLBACK_COLOR: [0, 0, 0, 0.1],
     GRID_FRAME_BACKGROUND_COLOR: 'rgb(250, 249, 251, 1)', // theme.backgroundSecondary
     GRID_FRAME_BACKGROUND_COLOR: 'rgb(250, 249, 251, 1)', // theme.backgroundSecondary
     GRID_LINE_COLOR: '#e5e7eb',
     GRID_LINE_COLOR: '#e5e7eb',
@@ -216,12 +224,15 @@ export const DarkFlamegraphTheme: FlamegraphTheme = {
       'by library': makeColorMapByLibrary,
       'by library': makeColorMapByLibrary,
       'by recursion': makeColorMapByRecursion,
       'by recursion': makeColorMapByRecursion,
       'by frequency': makeColorMapByFrequency,
       'by frequency': makeColorMapByFrequency,
+      'by system vs application frame': makeColorMapBySystemVsApplicationFrame,
     },
     },
     CURSOR_CROSSHAIR: '#828285',
     CURSOR_CROSSHAIR: '#828285',
     DIFFERENTIAL_DECREASE: [0.309, 0.2058, 0.98],
     DIFFERENTIAL_DECREASE: [0.309, 0.2058, 0.98],
     DIFFERENTIAL_INCREASE: [0.98, 0.2058, 0.4381],
     DIFFERENTIAL_INCREASE: [0.98, 0.2058, 0.4381],
     FOCUSED_FRAME_BORDER_COLOR: darkTheme.focus,
     FOCUSED_FRAME_BORDER_COLOR: darkTheme.focus,
     FRAME_GRAYSCALE_COLOR: [0.5, 0.5, 0.5, 0.4],
     FRAME_GRAYSCALE_COLOR: [0.5, 0.5, 0.5, 0.4],
+    FRAME_APPLICATION_COLOR: [0.1, 0.1, 0.8, 0.4],
+    FRAME_SYSTEM_COLOR: [0.7, 0.1, 0.1, 0.5],
     SPAN_FALLBACK_COLOR: [1, 1, 1, 0.3],
     SPAN_FALLBACK_COLOR: [1, 1, 1, 0.3],
     GRID_FRAME_BACKGROUND_COLOR: 'rgb(26, 20, 31,1)',
     GRID_FRAME_BACKGROUND_COLOR: 'rgb(26, 20, 31,1)',
     GRID_LINE_COLOR: '#222227',
     GRID_LINE_COLOR: '#222227',

Некоторые файлы не были показаны из-за большого количества измененных файлов