@red-hat-developer-hub/plugin-cost-management 2.0.3-rc.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +25 -0
- package/README.md +152 -0
- package/app-config.dynamic.yaml +28 -0
- package/dist/Router.esm.js +21 -0
- package/dist/Router.esm.js.map +1 -0
- package/dist/apis.esm.js +14 -0
- package/dist/apis.esm.js.map +1 -0
- package/dist/components/BasePage.esm.js +29 -0
- package/dist/components/BasePage.esm.js.map +1 -0
- package/dist/components/InfoCardTitle.esm.js +9 -0
- package/dist/components/InfoCardTitle.esm.js.map +1 -0
- package/dist/components/PageLayout.esm.js +56 -0
- package/dist/components/PageLayout.esm.js.map +1 -0
- package/dist/components/filtersStyles.esm.js +32 -0
- package/dist/components/filtersStyles.esm.js.map +1 -0
- package/dist/components/icon/AnalyticsIcon.esm.js +11 -0
- package/dist/components/icon/AnalyticsIcon.esm.js.map +1 -0
- package/dist/components/icon/AnalyticsIconFilled.esm.js +9 -0
- package/dist/components/icon/AnalyticsIconFilled.esm.js.map +1 -0
- package/dist/components/icon/AnalyticsIconOutlined.esm.js +9 -0
- package/dist/components/icon/AnalyticsIconOutlined.esm.js.map +1 -0
- package/dist/components/icon/CostManagementIcon.esm.js +11 -0
- package/dist/components/icon/CostManagementIcon.esm.js.map +1 -0
- package/dist/components/icon/CostManagementIconFilled.esm.js +9 -0
- package/dist/components/icon/CostManagementIconFilled.esm.js.map +1 -0
- package/dist/components/icon/CostManagementIconOutlined.esm.js +9 -0
- package/dist/components/icon/CostManagementIconOutlined.esm.js.map +1 -0
- package/dist/constants/currencies.esm.js +36 -0
- package/dist/constants/currencies.esm.js.map +1 -0
- package/dist/hooks/usePatternFlyTheme.esm.js +22 -0
- package/dist/hooks/usePatternFlyTheme.esm.js.map +1 -0
- package/dist/hooks/useThemeBackgroundColor.esm.js +13 -0
- package/dist/hooks/useThemeBackgroundColor.esm.js.map +1 -0
- package/dist/index.d.ts +71 -0
- package/dist/index.esm.js +9 -0
- package/dist/index.esm.js.map +1 -0
- package/dist/pages/openshift/OpenShiftPage.esm.js +727 -0
- package/dist/pages/openshift/OpenShiftPage.esm.js.map +1 -0
- package/dist/pages/openshift/components/AutocompleteComponent.esm.js +65 -0
- package/dist/pages/openshift/components/AutocompleteComponent.esm.js.map +1 -0
- package/dist/pages/openshift/components/DownloadIconButton.esm.js +49 -0
- package/dist/pages/openshift/components/DownloadIconButton.esm.js.map +1 -0
- package/dist/pages/openshift/components/Filters.esm.js +360 -0
- package/dist/pages/openshift/components/Filters.esm.js.map +1 -0
- package/dist/pages/openshift/components/PageHeader.esm.js +31 -0
- package/dist/pages/openshift/components/PageHeader.esm.js.map +1 -0
- package/dist/pages/openshift/components/SelectComponent.esm.js +68 -0
- package/dist/pages/openshift/components/SelectComponent.esm.js.map +1 -0
- package/dist/pages/openshift/components/TableToolbar.esm.js +249 -0
- package/dist/pages/openshift/components/TableToolbar.esm.js.map +1 -0
- package/dist/pages/optimizations/OptimizationsPage.esm.js +205 -0
- package/dist/pages/optimizations/OptimizationsPage.esm.js.map +1 -0
- package/dist/pages/optimizations/components/ComboBox.esm.js +84 -0
- package/dist/pages/optimizations/components/ComboBox.esm.js.map +1 -0
- package/dist/pages/optimizations/components/Filters.esm.js +59 -0
- package/dist/pages/optimizations/components/Filters.esm.js.map +1 -0
- package/dist/pages/optimizations/components/TableToolbar.esm.js +40 -0
- package/dist/pages/optimizations/components/TableToolbar.esm.js.map +1 -0
- package/dist/pages/optimizations-breakdown/OptimizationsBreakdownPage.esm.js +211 -0
- package/dist/pages/optimizations-breakdown/OptimizationsBreakdownPage.esm.js.map +1 -0
- package/dist/pages/optimizations-breakdown/components/optimization-engine-tab/OptimizationEngineTab.esm.js +132 -0
- package/dist/pages/optimizations-breakdown/components/optimization-engine-tab/OptimizationEngineTab.esm.js.map +1 -0
- package/dist/pages/optimizations-breakdown/components/optimization-engine-tab/components/CodeInfoCard.esm.js +37 -0
- package/dist/pages/optimizations-breakdown/components/optimization-engine-tab/components/CodeInfoCard.esm.js.map +1 -0
- package/dist/pages/optimizations-breakdown/components/optimization-engine-tab/components/ContainerInfoCard.esm.js +50 -0
- package/dist/pages/optimizations-breakdown/components/optimization-engine-tab/components/ContainerInfoCard.esm.js.map +1 -0
- package/dist/pages/optimizations-breakdown/components/optimization-engine-tab/components/chart-info-card/ChartInfoCard.esm.js +26 -0
- package/dist/pages/optimizations-breakdown/components/optimization-engine-tab/components/chart-info-card/ChartInfoCard.esm.js.map +1 -0
- package/dist/pages/optimizations-breakdown/components/optimization-engine-tab/components/chart-info-card/components/IntlBreakdownChart.esm.js +51 -0
- package/dist/pages/optimizations-breakdown/components/optimization-engine-tab/components/chart-info-card/components/IntlBreakdownChart.esm.js.map +1 -0
- package/dist/pages/optimizations-breakdown/components/optimization-engine-tab/components/chart-info-card/components/intl-breakdown-chart/components/optimizations-breakdown-chart/components/optimizations-breakdown-chart/OptimizationsBreakdownChart.esm.js +388 -0
- package/dist/pages/optimizations-breakdown/components/optimization-engine-tab/components/chart-info-card/components/intl-breakdown-chart/components/optimizations-breakdown-chart/components/optimizations-breakdown-chart/OptimizationsBreakdownChart.esm.js.map +1 -0
- package/dist/pages/optimizations-breakdown/components/optimization-engine-tab/components/chart-info-card/components/intl-breakdown-chart/components/optimizations-breakdown-chart/components/optimizations-breakdown-chart/i18n/data.json.esm.js +512 -0
- package/dist/pages/optimizations-breakdown/components/optimization-engine-tab/components/chart-info-card/components/intl-breakdown-chart/components/optimizations-breakdown-chart/components/optimizations-breakdown-chart/i18n/data.json.esm.js.map +1 -0
- package/dist/pages/optimizations-breakdown/components/optimization-engine-tab/components/chart-info-card/components/intl-breakdown-chart/components/optimizations-breakdown-chart/components/optimizations-breakdown-chart/i18n/intl.esm.js +18 -0
- package/dist/pages/optimizations-breakdown/components/optimization-engine-tab/components/chart-info-card/components/intl-breakdown-chart/components/optimizations-breakdown-chart/components/optimizations-breakdown-chart/i18n/intl.esm.js.map +1 -0
- package/dist/pages/optimizations-breakdown/components/optimization-engine-tab/components/chart-info-card/components/intl-breakdown-chart/components/optimizations-breakdown-chart/components/optimizations-breakdown-chart/i18n/messages.esm.js +72 -0
- package/dist/pages/optimizations-breakdown/components/optimization-engine-tab/components/chart-info-card/components/intl-breakdown-chart/components/optimizations-breakdown-chart/components/optimizations-breakdown-chart/i18n/messages.esm.js.map +1 -0
- package/dist/pages/optimizations-breakdown/components/optimization-engine-tab/components/chart-info-card/components/intl-breakdown-chart/components/optimizations-breakdown-chart/components/optimizations-breakdown-chart/utils/chart-data-format.esm.js +96 -0
- package/dist/pages/optimizations-breakdown/components/optimization-engine-tab/components/chart-info-card/components/intl-breakdown-chart/components/optimizations-breakdown-chart/components/optimizations-breakdown-chart/utils/chart-data-format.esm.js.map +1 -0
- package/dist/pages/optimizations-breakdown/components/optimization-engine-tab/components/chart-info-card/components/intl-breakdown-chart/components/optimizations-breakdown-chart/components/optimizations-breakdown-chart/utils/chart-datum.esm.js +74 -0
- package/dist/pages/optimizations-breakdown/components/optimization-engine-tab/components/chart-info-card/components/intl-breakdown-chart/components/optimizations-breakdown-chart/components/optimizations-breakdown-chart/utils/chart-datum.esm.js.map +1 -0
- package/dist/pages/optimizations-breakdown/components/optimization-engine-tab/components/chart-info-card/components/intl-breakdown-chart/components/optimizations-breakdown-chart/components/optimizations-breakdown-chart/utils/chart-utils.esm.js +109 -0
- package/dist/pages/optimizations-breakdown/components/optimization-engine-tab/components/chart-info-card/components/intl-breakdown-chart/components/optimizations-breakdown-chart/components/optimizations-breakdown-chart/utils/chart-utils.esm.js.map +1 -0
- package/dist/pages/optimizations-breakdown/components/optimization-engine-tab/components/chart-info-card/components/intl-breakdown-chart/components/optimizations-breakdown-chart/components/optimizations-breakdown-chart/utils/format.esm.js +25 -0
- package/dist/pages/optimizations-breakdown/components/optimization-engine-tab/components/chart-info-card/components/intl-breakdown-chart/components/optimizations-breakdown-chart/components/optimizations-breakdown-chart/utils/format.esm.js.map +1 -0
- package/dist/pages/optimizations-breakdown/models/ChartEnums.esm.js +23 -0
- package/dist/pages/optimizations-breakdown/models/ChartEnums.esm.js.map +1 -0
- package/dist/pages/optimizations-breakdown/models/YamlCodeData.esm.js +129 -0
- package/dist/pages/optimizations-breakdown/models/YamlCodeData.esm.js.map +1 -0
- package/dist/plugin.esm.js +73 -0
- package/dist/plugin.esm.js.map +1 -0
- package/dist/routes.esm.js +16 -0
- package/dist/routes.esm.js.map +1 -0
- package/dist/utils/dates.esm.js +37 -0
- package/dist/utils/dates.esm.js.map +1 -0
- package/package.json +110 -0
|
@@ -0,0 +1,388 @@
|
|
|
1
|
+
import React, { useState, useCallback, useMemo, useEffect } from 'react';
|
|
2
|
+
import { useIntl } from 'react-intl';
|
|
3
|
+
import { makeStyles } from '@material-ui/core/styles';
|
|
4
|
+
import { createContainer, Chart, ChartThemeColor, ChartAxis, ChartLegend, getInteractiveLegendEvents, ChartLegendTooltip, ChartArea, ChartScatter, ChartBoxPlot } from '@patternfly/react-charts/victory';
|
|
5
|
+
import { chart_color_blue_100 } from '@patternfly/react-tokens/dist/js/chart_color_blue_100';
|
|
6
|
+
import { chart_color_blue_200 } from '@patternfly/react-tokens/dist/js/chart_color_blue_200';
|
|
7
|
+
import { chart_color_blue_400 } from '@patternfly/react-tokens/dist/js/chart_color_blue_400';
|
|
8
|
+
import { chart_color_red_orange_200 } from '@patternfly/react-tokens/dist/js/chart_color_red_orange_200';
|
|
9
|
+
import { getResizeObserver, getDomain, getLegendData, isSeriesHidden, isDataAvailable, initHiddenSeries } from './utils/chart-utils.esm.js';
|
|
10
|
+
import messages from './i18n/messages.esm.js';
|
|
11
|
+
import { unitsLookupKey } from './utils/format.esm.js';
|
|
12
|
+
import { getDateRangeString } from './utils/chart-datum.esm.js';
|
|
13
|
+
|
|
14
|
+
const useOptimizationsBreakdownChartStyles = makeStyles(() => ({
|
|
15
|
+
chartOverride: {
|
|
16
|
+
"& > div > div > svg": {
|
|
17
|
+
overflow: "visible"
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
}));
|
|
21
|
+
const chartStyles = {
|
|
22
|
+
limit: {
|
|
23
|
+
fill: "none"
|
|
24
|
+
},
|
|
25
|
+
limitColorScale: [chart_color_red_orange_200.value],
|
|
26
|
+
request: {
|
|
27
|
+
fill: "none"
|
|
28
|
+
},
|
|
29
|
+
requestColorScale: [chart_color_blue_400.value],
|
|
30
|
+
usageColorScale: [chart_color_blue_100.value, chart_color_blue_200.value]
|
|
31
|
+
};
|
|
32
|
+
const OptimizationsBreakdownChart = ({ baseHeight, name, limitData, padding, requestData, usageData }) => {
|
|
33
|
+
const [containerRef] = useState(React.createRef());
|
|
34
|
+
const [cursorVoronoiContainer, setCursorVoronoiContainer] = useState();
|
|
35
|
+
const [extraHeight, setExtraHeight] = useState(0);
|
|
36
|
+
const [hiddenSeries, setHiddenSeries] = useState(/* @__PURE__ */ new Set());
|
|
37
|
+
const [series, setSeries] = useState();
|
|
38
|
+
const [width, setWidth] = useState(0);
|
|
39
|
+
const intl = useIntl();
|
|
40
|
+
const classes = useOptimizationsBreakdownChartStyles();
|
|
41
|
+
const cloneContainer = () => {
|
|
42
|
+
const legendData = getLegendData(series, hiddenSeries, true);
|
|
43
|
+
legendData?.push(
|
|
44
|
+
{
|
|
45
|
+
childName: "usage",
|
|
46
|
+
name: "",
|
|
47
|
+
symbol: {
|
|
48
|
+
fill: "none"
|
|
49
|
+
}
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
childName: "usage",
|
|
53
|
+
name: "",
|
|
54
|
+
symbol: {
|
|
55
|
+
fill: "none"
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
);
|
|
59
|
+
return cursorVoronoiContainer ? React.cloneElement(cursorVoronoiContainer, {
|
|
60
|
+
disable: !isDataAvailable(series, hiddenSeries),
|
|
61
|
+
labelComponent: /* @__PURE__ */ React.createElement(
|
|
62
|
+
ChartLegendTooltip,
|
|
63
|
+
{
|
|
64
|
+
legendData,
|
|
65
|
+
title: (datum) => `${datum.x}`
|
|
66
|
+
}
|
|
67
|
+
)
|
|
68
|
+
}) : void 0;
|
|
69
|
+
};
|
|
70
|
+
const getLimitChart = () => {
|
|
71
|
+
return series?.map((serie, index) => {
|
|
72
|
+
if (serie.childName === "limit") {
|
|
73
|
+
return /* @__PURE__ */ React.createElement(
|
|
74
|
+
ChartArea,
|
|
75
|
+
{
|
|
76
|
+
data: !hiddenSeries.has(index) ? serie.data : [{ y: null }],
|
|
77
|
+
interpolation: "monotoneX",
|
|
78
|
+
key: serie.childName,
|
|
79
|
+
name: serie.childName,
|
|
80
|
+
style: serie.style
|
|
81
|
+
}
|
|
82
|
+
);
|
|
83
|
+
}
|
|
84
|
+
return null;
|
|
85
|
+
});
|
|
86
|
+
};
|
|
87
|
+
const getRequestChart = () => {
|
|
88
|
+
return series?.map((serie, index) => {
|
|
89
|
+
if (serie.childName === "request") {
|
|
90
|
+
return /* @__PURE__ */ React.createElement(
|
|
91
|
+
ChartArea,
|
|
92
|
+
{
|
|
93
|
+
data: !hiddenSeries.has(index) ? serie.data : [{ y: null }],
|
|
94
|
+
interpolation: "monotoneX",
|
|
95
|
+
key: serie.childName,
|
|
96
|
+
name: serie.childName,
|
|
97
|
+
style: serie.style
|
|
98
|
+
}
|
|
99
|
+
);
|
|
100
|
+
}
|
|
101
|
+
return null;
|
|
102
|
+
});
|
|
103
|
+
};
|
|
104
|
+
const getScatterChart = () => {
|
|
105
|
+
return series?.map((serie, index) => {
|
|
106
|
+
if (serie.childName === "scatter") {
|
|
107
|
+
return /* @__PURE__ */ React.createElement(
|
|
108
|
+
ChartScatter,
|
|
109
|
+
{
|
|
110
|
+
data: !hiddenSeries.has(index - 1) ? serie.data : [{ y: null }],
|
|
111
|
+
key: serie.childName,
|
|
112
|
+
name: serie.childName,
|
|
113
|
+
style: serie.style
|
|
114
|
+
}
|
|
115
|
+
);
|
|
116
|
+
}
|
|
117
|
+
return null;
|
|
118
|
+
});
|
|
119
|
+
};
|
|
120
|
+
const getUsageChart = () => {
|
|
121
|
+
return series?.map((serie, index) => {
|
|
122
|
+
if (serie.childName === "usage") {
|
|
123
|
+
return /* @__PURE__ */ React.createElement(
|
|
124
|
+
ChartBoxPlot,
|
|
125
|
+
{
|
|
126
|
+
boxWidth: width < 475 ? 15 : void 0,
|
|
127
|
+
data: !hiddenSeries.has(index) ? serie.data : [{ y: [null] }],
|
|
128
|
+
key: serie.childName,
|
|
129
|
+
name: serie.childName,
|
|
130
|
+
style: serie.style
|
|
131
|
+
}
|
|
132
|
+
);
|
|
133
|
+
}
|
|
134
|
+
return null;
|
|
135
|
+
});
|
|
136
|
+
};
|
|
137
|
+
const getChartNames = () => {
|
|
138
|
+
const result = [];
|
|
139
|
+
if (series) {
|
|
140
|
+
series.forEach((serie) => {
|
|
141
|
+
if (serie.childName === "usage") {
|
|
142
|
+
result.push([serie.childName, "scatter"]);
|
|
143
|
+
} else if (serie.childName !== "scatter") {
|
|
144
|
+
result.push(serie.childName);
|
|
145
|
+
}
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
return result;
|
|
149
|
+
};
|
|
150
|
+
const getPadding = useCallback(() => {
|
|
151
|
+
return padding ? padding : {
|
|
152
|
+
bottom: 75 + extraHeight,
|
|
153
|
+
// Maintain chart aspect ratio
|
|
154
|
+
left: 50,
|
|
155
|
+
right: 50,
|
|
156
|
+
top: 10
|
|
157
|
+
};
|
|
158
|
+
}, [extraHeight, padding]);
|
|
159
|
+
const handleOnLegendClick = (index) => {
|
|
160
|
+
const newHiddenSeries = initHiddenSeries(hiddenSeries, index);
|
|
161
|
+
setHiddenSeries(newHiddenSeries);
|
|
162
|
+
};
|
|
163
|
+
const getCursorVoronoiContainer = useCallback(() => {
|
|
164
|
+
const CursorVoronoiContainer = createContainer("voronoi", "cursor");
|
|
165
|
+
const labelFormatter = (datum) => {
|
|
166
|
+
const formatValue = (val) => val !== void 0 ? val : "";
|
|
167
|
+
if (datum.childName === "scatter") {
|
|
168
|
+
return null;
|
|
169
|
+
} else if (datum.childName === "usage" && (datum._min !== void 0 || datum._max !== void 0 || datum._median !== void 0 || datum._q1 !== void 0 || datum._q3 !== void 0 || datum.yVal !== null)) {
|
|
170
|
+
return intl.formatMessage(messages.chartUsageTooltip, {
|
|
171
|
+
br: "\n",
|
|
172
|
+
min: formatValue(datum._min !== void 0 ? datum._min : datum.yVal),
|
|
173
|
+
max: formatValue(datum._max !== void 0 ? datum._max : datum.yVal),
|
|
174
|
+
median: formatValue(
|
|
175
|
+
datum._median !== void 0 ? datum._median : datum.yVal
|
|
176
|
+
),
|
|
177
|
+
q1: formatValue(datum._q1 !== void 0 ? datum._q1 : datum.yVal),
|
|
178
|
+
q3: formatValue(datum._q3 !== void 0 ? datum._q3 : datum.yVal),
|
|
179
|
+
units: intl.formatMessage(messages.units, {
|
|
180
|
+
units: unitsLookupKey(datum.units)
|
|
181
|
+
})
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
const yVal = Array.isArray(datum.y) ? datum.y[0] : datum.y;
|
|
185
|
+
let units = datum.units;
|
|
186
|
+
if ((datum.childName === "limit" || datum.childName === "request") && datum.units === "") {
|
|
187
|
+
units = unitsLookupKey("cores");
|
|
188
|
+
}
|
|
189
|
+
return yVal !== null ? intl.formatMessage(messages.valueUnits, {
|
|
190
|
+
value: yVal,
|
|
191
|
+
units: intl.formatMessage(messages.units, {
|
|
192
|
+
units: unitsLookupKey(units)
|
|
193
|
+
})
|
|
194
|
+
}) : intl.formatMessage(messages.chartNoData);
|
|
195
|
+
};
|
|
196
|
+
return /* @__PURE__ */ React.createElement(
|
|
197
|
+
CursorVoronoiContainer,
|
|
198
|
+
{
|
|
199
|
+
cursorDimension: "x",
|
|
200
|
+
labels: ({ datum }) => labelFormatter(datum),
|
|
201
|
+
mouseFollowTooltips: true,
|
|
202
|
+
voronoiDimension: "x",
|
|
203
|
+
voronoiPadding: getPadding()
|
|
204
|
+
}
|
|
205
|
+
);
|
|
206
|
+
}, [getPadding, intl]);
|
|
207
|
+
const getEvents = () => {
|
|
208
|
+
const result = getInteractiveLegendEvents({
|
|
209
|
+
chartNames: getChartNames(),
|
|
210
|
+
isHidden: (index) => isSeriesHidden(hiddenSeries, index),
|
|
211
|
+
legendName: `${name}-legend`,
|
|
212
|
+
onLegendClick: (props) => handleOnLegendClick(props.index)
|
|
213
|
+
});
|
|
214
|
+
return result;
|
|
215
|
+
};
|
|
216
|
+
const getHeight = () => {
|
|
217
|
+
return baseHeight + extraHeight;
|
|
218
|
+
};
|
|
219
|
+
const getLegend = () => {
|
|
220
|
+
return /* @__PURE__ */ React.createElement(
|
|
221
|
+
ChartLegend,
|
|
222
|
+
{
|
|
223
|
+
data: getLegendData(series, hiddenSeries),
|
|
224
|
+
gutter: 20,
|
|
225
|
+
name: `${name}-legend`,
|
|
226
|
+
y: 320
|
|
227
|
+
}
|
|
228
|
+
);
|
|
229
|
+
};
|
|
230
|
+
const handleLegendAllowWrap = (value) => {
|
|
231
|
+
if (value !== extraHeight) {
|
|
232
|
+
setExtraHeight(value);
|
|
233
|
+
}
|
|
234
|
+
};
|
|
235
|
+
const handleOnResize = useCallback(() => {
|
|
236
|
+
const { clientWidth = 0 } = containerRef.current || {};
|
|
237
|
+
if (clientWidth !== width) {
|
|
238
|
+
setWidth(clientWidth);
|
|
239
|
+
}
|
|
240
|
+
}, [containerRef, width]);
|
|
241
|
+
const initDatum = useCallback(() => {
|
|
242
|
+
const newSeries = [];
|
|
243
|
+
if (requestData && requestData.length) {
|
|
244
|
+
newSeries.push({
|
|
245
|
+
childName: "request",
|
|
246
|
+
data: requestData,
|
|
247
|
+
legendItem: {
|
|
248
|
+
name: getDateRangeString(
|
|
249
|
+
requestData,
|
|
250
|
+
messages.recommendedRequest,
|
|
251
|
+
true
|
|
252
|
+
),
|
|
253
|
+
symbol: {
|
|
254
|
+
fill: chartStyles.requestColorScale[0],
|
|
255
|
+
type: "square"
|
|
256
|
+
},
|
|
257
|
+
tooltip: intl.formatMessage(messages.request)
|
|
258
|
+
},
|
|
259
|
+
style: {
|
|
260
|
+
data: {
|
|
261
|
+
...chartStyles.request,
|
|
262
|
+
stroke: chartStyles.requestColorScale[0]
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
});
|
|
266
|
+
}
|
|
267
|
+
if (limitData && limitData.length) {
|
|
268
|
+
newSeries.push({
|
|
269
|
+
childName: "limit",
|
|
270
|
+
data: limitData,
|
|
271
|
+
legendItem: {
|
|
272
|
+
name: getDateRangeString(limitData, messages.recommendedLimit, true),
|
|
273
|
+
symbol: {
|
|
274
|
+
fill: chartStyles.limitColorScale[0],
|
|
275
|
+
type: "square"
|
|
276
|
+
},
|
|
277
|
+
tooltip: intl.formatMessage(messages.limit)
|
|
278
|
+
},
|
|
279
|
+
style: {
|
|
280
|
+
data: {
|
|
281
|
+
...chartStyles.limit,
|
|
282
|
+
stroke: chartStyles.limitColorScale[0]
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
});
|
|
286
|
+
}
|
|
287
|
+
if (usageData && usageData.length) {
|
|
288
|
+
const boxPlotData = [];
|
|
289
|
+
usageData.map((datum) => {
|
|
290
|
+
if (datum.y.every((val, _i, arr) => val === arr[0])) {
|
|
291
|
+
boxPlotData.push({
|
|
292
|
+
...datum,
|
|
293
|
+
yVal: datum.y[0],
|
|
294
|
+
y: [null]
|
|
295
|
+
});
|
|
296
|
+
} else {
|
|
297
|
+
boxPlotData.push(datum);
|
|
298
|
+
}
|
|
299
|
+
});
|
|
300
|
+
newSeries.push({
|
|
301
|
+
childName: "usage",
|
|
302
|
+
data: boxPlotData,
|
|
303
|
+
legendItem: {
|
|
304
|
+
name: getDateRangeString(usageData, messages.actualUsage),
|
|
305
|
+
symbol: {
|
|
306
|
+
fill: chartStyles.usageColorScale[1],
|
|
307
|
+
type: "square"
|
|
308
|
+
},
|
|
309
|
+
tooltip: intl.formatMessage(messages.usage)
|
|
310
|
+
},
|
|
311
|
+
style: {
|
|
312
|
+
median: {
|
|
313
|
+
stroke: chartStyles.usageColorScale[0]
|
|
314
|
+
},
|
|
315
|
+
q1: {
|
|
316
|
+
fill: chartStyles.usageColorScale[1]
|
|
317
|
+
},
|
|
318
|
+
q3: {
|
|
319
|
+
fill: chartStyles.usageColorScale[1]
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
});
|
|
323
|
+
const scatterData = [];
|
|
324
|
+
usageData.map((datum) => {
|
|
325
|
+
if (datum.y.every((val, _i, arr) => val === arr[0])) {
|
|
326
|
+
scatterData.push({
|
|
327
|
+
...datum,
|
|
328
|
+
y: datum.y[0]
|
|
329
|
+
});
|
|
330
|
+
} else {
|
|
331
|
+
scatterData.push({
|
|
332
|
+
...datum,
|
|
333
|
+
y: null
|
|
334
|
+
});
|
|
335
|
+
}
|
|
336
|
+
});
|
|
337
|
+
newSeries.push({
|
|
338
|
+
childName: "scatter",
|
|
339
|
+
data: scatterData,
|
|
340
|
+
style: {
|
|
341
|
+
data: { fill: chartStyles.usageColorScale[1] }
|
|
342
|
+
}
|
|
343
|
+
});
|
|
344
|
+
}
|
|
345
|
+
setSeries(newSeries);
|
|
346
|
+
setCursorVoronoiContainer(getCursorVoronoiContainer());
|
|
347
|
+
setHiddenSeries(/* @__PURE__ */ new Set());
|
|
348
|
+
}, [getCursorVoronoiContainer, intl, limitData, requestData, usageData]);
|
|
349
|
+
useMemo(() => {
|
|
350
|
+
initDatum();
|
|
351
|
+
}, [initDatum]);
|
|
352
|
+
useEffect(() => {
|
|
353
|
+
const unobserve = getResizeObserver(containerRef.current, handleOnResize);
|
|
354
|
+
return () => {
|
|
355
|
+
if (unobserve) {
|
|
356
|
+
unobserve();
|
|
357
|
+
}
|
|
358
|
+
};
|
|
359
|
+
}, [containerRef, handleOnResize]);
|
|
360
|
+
const chartHeight = getHeight();
|
|
361
|
+
return /* @__PURE__ */ React.createElement("div", { className: classes.chartOverride, ref: containerRef }, /* @__PURE__ */ React.createElement("div", { style: { height: chartHeight } }, /* @__PURE__ */ React.createElement(
|
|
362
|
+
Chart,
|
|
363
|
+
{
|
|
364
|
+
key: `chart-${name}`,
|
|
365
|
+
containerComponent: cloneContainer(),
|
|
366
|
+
domain: getDomain(series, hiddenSeries, 1),
|
|
367
|
+
domainPadding: { x: [30, 30] },
|
|
368
|
+
events: getEvents(),
|
|
369
|
+
height: chartHeight,
|
|
370
|
+
legendAllowWrap: handleLegendAllowWrap,
|
|
371
|
+
legendComponent: getLegend(),
|
|
372
|
+
legendPosition: "bottom",
|
|
373
|
+
name,
|
|
374
|
+
padding: getPadding(),
|
|
375
|
+
width,
|
|
376
|
+
themeColor: ChartThemeColor.default
|
|
377
|
+
},
|
|
378
|
+
/* @__PURE__ */ React.createElement(ChartAxis, { fixLabelOverlap: true }),
|
|
379
|
+
/* @__PURE__ */ React.createElement(ChartAxis, { dependentAxis: true, showGrid: true }),
|
|
380
|
+
getRequestChart(),
|
|
381
|
+
getLimitChart(),
|
|
382
|
+
getScatterChart(),
|
|
383
|
+
getUsageChart()
|
|
384
|
+
)));
|
|
385
|
+
};
|
|
386
|
+
|
|
387
|
+
export { OptimizationsBreakdownChart, chartStyles };
|
|
388
|
+
//# sourceMappingURL=OptimizationsBreakdownChart.esm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"OptimizationsBreakdownChart.esm.js","sources":["../../../../../../../../../../../../../src/pages/optimizations-breakdown/components/optimization-engine-tab/components/chart-info-card/components/intl-breakdown-chart/components/optimizations-breakdown-chart/components/optimizations-breakdown-chart/OptimizationsBreakdownChart.tsx"],"sourcesContent":["/*\n * Copyright Red Hat, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport React, { useCallback, useEffect, useMemo, useState } from 'react';\nimport { useIntl } from 'react-intl';\nimport { makeStyles } from '@material-ui/core/styles';\nimport {\n Chart,\n ChartArea,\n ChartAxis,\n ChartBoxPlot,\n ChartLegend,\n ChartLegendTooltip,\n ChartScatter,\n createContainer,\n getInteractiveLegendEvents,\n ChartThemeColor,\n} from '@patternfly/react-charts/victory';\nimport { chart_color_blue_100 } from '@patternfly/react-tokens/dist/js/chart_color_blue_100';\nimport { chart_color_blue_200 } from '@patternfly/react-tokens/dist/js/chart_color_blue_200';\nimport { chart_color_blue_400 } from '@patternfly/react-tokens/dist/js/chart_color_blue_400';\nimport { chart_color_red_orange_200 } from '@patternfly/react-tokens/dist/js/chart_color_red_orange_200';\nimport { ChartSeries } from './types/ChartSeries';\nimport {\n getDomain,\n getLegendData,\n getResizeObserver,\n initHiddenSeries,\n isDataAvailable,\n isSeriesHidden,\n} from './utils/chart-utils';\nimport messages from './i18n/messages';\nimport { unitsLookupKey } from './utils/format';\nimport { getDateRangeString } from './utils/chart-datum';\n\nconst useOptimizationsBreakdownChartStyles = makeStyles(() => ({\n chartOverride: {\n '& > div > div > svg': {\n overflow: 'visible',\n },\n },\n}));\n\nexport const chartStyles = {\n limit: {\n fill: 'none',\n },\n limitColorScale: [chart_color_red_orange_200.value],\n request: {\n fill: 'none',\n },\n requestColorScale: [chart_color_blue_400.value],\n usageColorScale: [chart_color_blue_100.value, chart_color_blue_200.value],\n};\n\ninterface OptimizationsBreakdownChartOwnProps {\n baseHeight: number;\n limitData?: any;\n name?: string;\n padding?: any;\n requestData?: any;\n usageData?: any;\n}\n\ntype OptimizationsBreakdownChartProps = OptimizationsBreakdownChartOwnProps;\n\nconst OptimizationsBreakdownChart: React.FC<\n OptimizationsBreakdownChartProps\n> = ({ baseHeight, name, limitData, padding, requestData, usageData }) => {\n const [containerRef] = useState(React.createRef<HTMLDivElement>());\n const [cursorVoronoiContainer, setCursorVoronoiContainer] = useState<any>();\n const [extraHeight, setExtraHeight] = useState(0);\n const [hiddenSeries, setHiddenSeries] = useState(new Set<number>());\n const [series, setSeries] = useState<ChartSeries[]>();\n const [width, setWidth] = useState(0);\n\n const intl = useIntl();\n const classes = useOptimizationsBreakdownChartStyles();\n\n // Clone original container. See https://issues.redhat.com/browse/COST-762\n const cloneContainer = () => {\n const legendData = getLegendData(series, hiddenSeries, true);\n // Force extra space for line wrapping\n legendData?.push(\n {\n childName: 'usage',\n name: '',\n symbol: {\n fill: 'none',\n },\n },\n {\n childName: 'usage',\n name: '',\n symbol: {\n fill: 'none',\n },\n },\n );\n return cursorVoronoiContainer\n ? React.cloneElement(cursorVoronoiContainer, {\n disable: !isDataAvailable(series, hiddenSeries),\n labelComponent: (\n <ChartLegendTooltip\n legendData={legendData}\n title={datum => `${datum.x}`}\n />\n ),\n } as any)\n : undefined;\n };\n\n const getLimitChart = () => {\n return series?.map((serie, index) => {\n if (serie.childName === 'limit') {\n return (\n <ChartArea\n data={!hiddenSeries.has(index) ? serie.data : [{ y: null }]}\n interpolation=\"monotoneX\"\n key={serie.childName}\n name={serie.childName}\n style={serie.style}\n />\n );\n }\n return null;\n });\n };\n\n const getRequestChart = () => {\n return series?.map((serie, index) => {\n if (serie.childName === 'request') {\n return (\n <ChartArea\n data={!hiddenSeries.has(index) ? serie.data : [{ y: null }]}\n interpolation=\"monotoneX\"\n key={serie.childName}\n name={serie.childName}\n style={serie.style}\n />\n );\n }\n return null;\n });\n };\n\n const getScatterChart = () => {\n return series?.map((serie, index) => {\n if (serie.childName === 'scatter') {\n return (\n <ChartScatter\n data={!hiddenSeries.has(index - 1) ? serie.data : [{ y: null }]}\n key={serie.childName}\n name={serie.childName}\n style={serie.style}\n />\n );\n }\n return null;\n });\n };\n\n const getUsageChart = () => {\n return series?.map((serie, index) => {\n if (serie.childName === 'usage') {\n return (\n <ChartBoxPlot\n boxWidth={width < 475 ? 15 : undefined}\n data={!hiddenSeries.has(index) ? serie.data : [{ y: [null] }]}\n key={serie.childName}\n name={serie.childName}\n style={serie.style}\n />\n );\n }\n return null;\n });\n };\n\n // Returns groups of chart names associated with each data series\n const getChartNames = () => {\n const result: (string | string[] | undefined)[] = [];\n\n if (series) {\n series.forEach(serie => {\n // Each group of chart names are hidden / shown together\n if (serie.childName === 'usage') {\n result.push([serie.childName, 'scatter']);\n } else if (serie.childName !== 'scatter') {\n result.push(serie.childName);\n }\n });\n }\n return result as any;\n };\n\n const getPadding = useCallback(() => {\n return padding\n ? padding\n : {\n bottom: 75 + extraHeight, // Maintain chart aspect ratio\n left: 50,\n right: 50,\n top: 10,\n };\n }, [extraHeight, padding]);\n\n // Hide each data series individually\n const handleOnLegendClick = (index: number) => {\n const newHiddenSeries = initHiddenSeries(hiddenSeries, index);\n setHiddenSeries(newHiddenSeries);\n };\n\n // Returns CursorVoronoiContainer component\n const getCursorVoronoiContainer = useCallback(() => {\n // Note: Container order is important\n const CursorVoronoiContainer: any = createContainer('voronoi', 'cursor');\n\n const labelFormatter = (datum: {\n childName: string;\n _min: undefined;\n _max: undefined;\n _median: undefined;\n _q1: undefined;\n _q3: undefined;\n yVal: null;\n units: string;\n y: any[];\n }) => {\n const formatValue = (val: undefined | null) =>\n val !== undefined ? val : '';\n if (datum.childName === 'scatter') {\n return null;\n } else if (\n datum.childName === 'usage' &&\n (datum._min !== undefined ||\n datum._max !== undefined ||\n datum._median !== undefined ||\n datum._q1 !== undefined ||\n datum._q3 !== undefined ||\n datum.yVal !== null)\n ) {\n return intl.formatMessage(messages.chartUsageTooltip, {\n br: '\\n',\n min: formatValue(datum._min !== undefined ? datum._min : datum.yVal),\n max: formatValue(datum._max !== undefined ? datum._max : datum.yVal),\n median: formatValue(\n datum._median !== undefined ? datum._median : datum.yVal,\n ),\n q1: formatValue(datum._q1 !== undefined ? datum._q1 : datum.yVal),\n q3: formatValue(datum._q3 !== undefined ? datum._q3 : datum.yVal),\n units: intl.formatMessage(messages.units, {\n units: unitsLookupKey(datum.units),\n }),\n });\n }\n\n // With box plot, datum.y will be an array\n const yVal = Array.isArray(datum.y) ? datum.y[0] : datum.y;\n let units = datum.units;\n\n /**\n * The recommendations API intentionally omits CPU request and limit units when \"cores\".\n *\n * The yaml format for the resource units needs to adhere to the Kubernetes standard that is outlined here\n * https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/\n *\n * Example. \"45 millicores\" is represented as \"45m\", 64 MiB is represented as \"64Mi\",\n * 2.3 cores is represented as \"2.3\" (Note cores is not specified)\n */\n if (\n (datum.childName === 'limit' || datum.childName === 'request') &&\n datum.units === ''\n ) {\n units = unitsLookupKey('cores');\n }\n return yVal !== null\n ? intl.formatMessage(messages.valueUnits, {\n value: yVal,\n units: intl.formatMessage(messages.units, {\n units: unitsLookupKey(units),\n }),\n })\n : intl.formatMessage(messages.chartNoData);\n };\n\n return (\n <CursorVoronoiContainer\n cursorDimension=\"x\"\n labels={({ datum }: any) => labelFormatter(datum)}\n mouseFollowTooltips\n voronoiDimension=\"x\"\n voronoiPadding={getPadding()}\n />\n );\n }, [getPadding, intl]);\n\n // Returns onMouseOver, onMouseOut, and onClick events for the interactive legend\n const getEvents = () => {\n const result = getInteractiveLegendEvents({\n chartNames: getChartNames(),\n isHidden: index => isSeriesHidden(hiddenSeries, index),\n legendName: `${name}-legend`,\n onLegendClick: props => handleOnLegendClick(props.index),\n });\n return result;\n };\n\n const getHeight = () => {\n return baseHeight + extraHeight;\n };\n\n const getLegend = () => {\n return (\n <ChartLegend\n data={getLegendData(series, hiddenSeries)}\n gutter={20}\n name={`${name}-legend`}\n y={320}\n />\n );\n };\n\n const handleLegendAllowWrap = (value: number) => {\n if (value !== extraHeight) {\n setExtraHeight(value);\n }\n };\n\n const handleOnResize = useCallback(() => {\n const { clientWidth = 0 } = containerRef.current || {};\n\n if (clientWidth !== width) {\n setWidth(clientWidth);\n }\n }, [containerRef, width]);\n\n const initDatum = useCallback(() => {\n // Show all legends, regardless of data size\n\n const newSeries: ChartSeries[] = [];\n if (requestData && requestData.length) {\n newSeries.push({\n childName: 'request',\n data: requestData,\n legendItem: {\n name: getDateRangeString(\n requestData,\n messages.recommendedRequest,\n true,\n ),\n symbol: {\n fill: chartStyles.requestColorScale[0],\n type: 'square',\n },\n tooltip: intl.formatMessage(messages.request),\n },\n style: {\n data: {\n ...chartStyles.request,\n stroke: chartStyles.requestColorScale[0],\n },\n },\n });\n }\n if (limitData && limitData.length) {\n newSeries.push({\n childName: 'limit',\n data: limitData,\n legendItem: {\n name: getDateRangeString(limitData, messages.recommendedLimit, true),\n symbol: {\n fill: chartStyles.limitColorScale[0],\n type: 'square',\n },\n tooltip: intl.formatMessage(messages.limit),\n },\n style: {\n data: {\n ...chartStyles.limit,\n stroke: chartStyles.limitColorScale[0],\n },\n },\n });\n }\n if (usageData && usageData.length) {\n const boxPlotData: any[] = [];\n usageData.map((datum: any) => {\n if (datum.y.every((val: any, _i: any, arr: any[]) => val === arr[0])) {\n boxPlotData.push({\n ...datum,\n yVal: datum.y[0],\n y: [null],\n });\n } else {\n boxPlotData.push(datum);\n }\n });\n newSeries.push({\n childName: 'usage',\n data: boxPlotData as any,\n legendItem: {\n name: getDateRangeString(usageData, messages.actualUsage),\n symbol: {\n fill: chartStyles.usageColorScale[1],\n type: 'square',\n },\n tooltip: intl.formatMessage(messages.usage),\n },\n style: {\n median: {\n stroke: chartStyles.usageColorScale[0],\n },\n q1: {\n fill: chartStyles.usageColorScale[1],\n },\n q3: {\n fill: chartStyles.usageColorScale[1],\n },\n } as any,\n });\n\n // Show dots in place of box plot when all values are equal\n const scatterData: any[] = [];\n usageData.map((datum: any) => {\n if (datum.y.every((val: any, _i: any, arr: any[]) => val === arr[0])) {\n scatterData.push({\n ...datum,\n y: datum.y[0],\n });\n } else {\n scatterData.push({\n ...datum,\n y: null,\n });\n }\n });\n newSeries.push({\n childName: 'scatter',\n data: scatterData as any,\n style: {\n data: { fill: chartStyles.usageColorScale[1] },\n } as any,\n });\n }\n setSeries(newSeries);\n setCursorVoronoiContainer(getCursorVoronoiContainer());\n setHiddenSeries(new Set());\n }, [getCursorVoronoiContainer, intl, limitData, requestData, usageData]);\n\n useMemo(() => {\n initDatum();\n }, [initDatum]);\n\n useEffect(() => {\n const unobserve = getResizeObserver(containerRef.current, handleOnResize);\n return () => {\n if (unobserve) {\n unobserve();\n }\n };\n }, [containerRef, handleOnResize]);\n\n const chartHeight = getHeight();\n\n return (\n <div className={classes.chartOverride} ref={containerRef}>\n <div style={{ height: chartHeight }}>\n <Chart\n key={`chart-${name}`}\n containerComponent={cloneContainer()}\n domain={getDomain(series, hiddenSeries, 1)}\n domainPadding={{ x: [30, 30] }}\n events={getEvents()}\n height={chartHeight}\n legendAllowWrap={handleLegendAllowWrap}\n legendComponent={getLegend()}\n legendPosition=\"bottom\"\n name={name}\n padding={getPadding()}\n width={width}\n // PatternFly will handle theming automatically when pf-v6-theme-dark is applied\n themeColor={ChartThemeColor.default}\n >\n <ChartAxis fixLabelOverlap />\n <ChartAxis dependentAxis showGrid />\n {getRequestChart()}\n {getLimitChart()}\n {getScatterChart()}\n {getUsageChart()}\n </Chart>\n </div>\n </div>\n );\n};\n\nexport { OptimizationsBreakdownChart };\n"],"names":[],"mappings":";;;;;;;;;;;;;AAgDA,MAAM,oCAAA,GAAuC,WAAW,OAAO;AAAA,EAC7D,aAAe,EAAA;AAAA,IACb,qBAAuB,EAAA;AAAA,MACrB,QAAU,EAAA;AAAA;AACZ;AAEJ,CAAE,CAAA,CAAA;AAEK,MAAM,WAAc,GAAA;AAAA,EACzB,KAAO,EAAA;AAAA,IACL,IAAM,EAAA;AAAA,GACR;AAAA,EACA,eAAA,EAAiB,CAAC,0BAAA,CAA2B,KAAK,CAAA;AAAA,EAClD,OAAS,EAAA;AAAA,IACP,IAAM,EAAA;AAAA,GACR;AAAA,EACA,iBAAA,EAAmB,CAAC,oBAAA,CAAqB,KAAK,CAAA;AAAA,EAC9C,eAAiB,EAAA,CAAC,oBAAqB,CAAA,KAAA,EAAO,qBAAqB,KAAK;AAC1E;AAaM,MAAA,2BAAA,GAEF,CAAC,EAAE,UAAA,EAAY,MAAM,SAAW,EAAA,OAAA,EAAS,WAAa,EAAA,SAAA,EAAgB,KAAA;AACxE,EAAA,MAAM,CAAC,YAAY,CAAA,GAAI,QAAS,CAAA,KAAA,CAAM,WAA2B,CAAA;AACjE,EAAA,MAAM,CAAC,sBAAA,EAAwB,yBAAyB,CAAA,GAAI,QAAc,EAAA;AAC1E,EAAA,MAAM,CAAC,WAAA,EAAa,cAAc,CAAA,GAAI,SAAS,CAAC,CAAA;AAChD,EAAA,MAAM,CAAC,YAAc,EAAA,eAAe,IAAI,QAAS,iBAAA,IAAI,KAAa,CAAA;AAClE,EAAA,MAAM,CAAC,MAAA,EAAQ,SAAS,CAAA,GAAI,QAAwB,EAAA;AACpD,EAAA,MAAM,CAAC,KAAA,EAAO,QAAQ,CAAA,GAAI,SAAS,CAAC,CAAA;AAEpC,EAAA,MAAM,OAAO,OAAQ,EAAA;AACrB,EAAA,MAAM,UAAU,oCAAqC,EAAA;AAGrD,EAAA,MAAM,iBAAiB,MAAM;AAC3B,IAAA,MAAM,UAAa,GAAA,aAAA,CAAc,MAAQ,EAAA,YAAA,EAAc,IAAI,CAAA;AAE3D,IAAY,UAAA,EAAA,IAAA;AAAA,MACV;AAAA,QACE,SAAW,EAAA,OAAA;AAAA,QACX,IAAM,EAAA,EAAA;AAAA,QACN,MAAQ,EAAA;AAAA,UACN,IAAM,EAAA;AAAA;AACR,OACF;AAAA,MACA;AAAA,QACE,SAAW,EAAA,OAAA;AAAA,QACX,IAAM,EAAA,EAAA;AAAA,QACN,MAAQ,EAAA;AAAA,UACN,IAAM,EAAA;AAAA;AACR;AACF,KACF;AACA,IAAO,OAAA,sBAAA,GACH,KAAM,CAAA,YAAA,CAAa,sBAAwB,EAAA;AAAA,MACzC,OAAS,EAAA,CAAC,eAAgB,CAAA,MAAA,EAAQ,YAAY,CAAA;AAAA,MAC9C,cACE,kBAAA,KAAA,CAAA,aAAA;AAAA,QAAC,kBAAA;AAAA,QAAA;AAAA,UACC,UAAA;AAAA,UACA,KAAO,EAAA,CAAA,KAAA,KAAS,CAAG,EAAA,KAAA,CAAM,CAAC,CAAA;AAAA;AAAA;AAC5B,KAEI,CACR,GAAA,MAAA;AAAA,GACN;AAEA,EAAA,MAAM,gBAAgB,MAAM;AAC1B,IAAA,OAAO,MAAQ,EAAA,GAAA,CAAI,CAAC,KAAA,EAAO,KAAU,KAAA;AACnC,MAAI,IAAA,KAAA,CAAM,cAAc,OAAS,EAAA;AAC/B,QACE,uBAAA,KAAA,CAAA,aAAA;AAAA,UAAC,SAAA;AAAA,UAAA;AAAA,YACC,IAAM,EAAA,CAAC,YAAa,CAAA,GAAA,CAAI,KAAK,CAAA,GAAI,KAAM,CAAA,IAAA,GAAO,CAAC,EAAE,CAAG,EAAA,IAAA,EAAM,CAAA;AAAA,YAC1D,aAAc,EAAA,WAAA;AAAA,YACd,KAAK,KAAM,CAAA,SAAA;AAAA,YACX,MAAM,KAAM,CAAA,SAAA;AAAA,YACZ,OAAO,KAAM,CAAA;AAAA;AAAA,SACf;AAAA;AAGJ,MAAO,OAAA,IAAA;AAAA,KACR,CAAA;AAAA,GACH;AAEA,EAAA,MAAM,kBAAkB,MAAM;AAC5B,IAAA,OAAO,MAAQ,EAAA,GAAA,CAAI,CAAC,KAAA,EAAO,KAAU,KAAA;AACnC,MAAI,IAAA,KAAA,CAAM,cAAc,SAAW,EAAA;AACjC,QACE,uBAAA,KAAA,CAAA,aAAA;AAAA,UAAC,SAAA;AAAA,UAAA;AAAA,YACC,IAAM,EAAA,CAAC,YAAa,CAAA,GAAA,CAAI,KAAK,CAAA,GAAI,KAAM,CAAA,IAAA,GAAO,CAAC,EAAE,CAAG,EAAA,IAAA,EAAM,CAAA;AAAA,YAC1D,aAAc,EAAA,WAAA;AAAA,YACd,KAAK,KAAM,CAAA,SAAA;AAAA,YACX,MAAM,KAAM,CAAA,SAAA;AAAA,YACZ,OAAO,KAAM,CAAA;AAAA;AAAA,SACf;AAAA;AAGJ,MAAO,OAAA,IAAA;AAAA,KACR,CAAA;AAAA,GACH;AAEA,EAAA,MAAM,kBAAkB,MAAM;AAC5B,IAAA,OAAO,MAAQ,EAAA,GAAA,CAAI,CAAC,KAAA,EAAO,KAAU,KAAA;AACnC,MAAI,IAAA,KAAA,CAAM,cAAc,SAAW,EAAA;AACjC,QACE,uBAAA,KAAA,CAAA,aAAA;AAAA,UAAC,YAAA;AAAA,UAAA;AAAA,YACC,IAAM,EAAA,CAAC,YAAa,CAAA,GAAA,CAAI,KAAQ,GAAA,CAAC,CAAI,GAAA,KAAA,CAAM,IAAO,GAAA,CAAC,EAAE,CAAA,EAAG,MAAM,CAAA;AAAA,YAC9D,KAAK,KAAM,CAAA,SAAA;AAAA,YACX,MAAM,KAAM,CAAA,SAAA;AAAA,YACZ,OAAO,KAAM,CAAA;AAAA;AAAA,SACf;AAAA;AAGJ,MAAO,OAAA,IAAA;AAAA,KACR,CAAA;AAAA,GACH;AAEA,EAAA,MAAM,gBAAgB,MAAM;AAC1B,IAAA,OAAO,MAAQ,EAAA,GAAA,CAAI,CAAC,KAAA,EAAO,KAAU,KAAA;AACnC,MAAI,IAAA,KAAA,CAAM,cAAc,OAAS,EAAA;AAC/B,QACE,uBAAA,KAAA,CAAA,aAAA;AAAA,UAAC,YAAA;AAAA,UAAA;AAAA,YACC,QAAA,EAAU,KAAQ,GAAA,GAAA,GAAM,EAAK,GAAA,MAAA;AAAA,YAC7B,IAAM,EAAA,CAAC,YAAa,CAAA,GAAA,CAAI,KAAK,CAAI,GAAA,KAAA,CAAM,IAAO,GAAA,CAAC,EAAE,CAAA,EAAG,CAAC,IAAI,GAAG,CAAA;AAAA,YAC5D,KAAK,KAAM,CAAA,SAAA;AAAA,YACX,MAAM,KAAM,CAAA,SAAA;AAAA,YACZ,OAAO,KAAM,CAAA;AAAA;AAAA,SACf;AAAA;AAGJ,MAAO,OAAA,IAAA;AAAA,KACR,CAAA;AAAA,GACH;AAGA,EAAA,MAAM,gBAAgB,MAAM;AAC1B,IAAA,MAAM,SAA4C,EAAC;AAEnD,IAAA,IAAI,MAAQ,EAAA;AACV,MAAA,MAAA,CAAO,QAAQ,CAAS,KAAA,KAAA;AAEtB,QAAI,IAAA,KAAA,CAAM,cAAc,OAAS,EAAA;AAC/B,UAAA,MAAA,CAAO,IAAK,CAAA,CAAC,KAAM,CAAA,SAAA,EAAW,SAAS,CAAC,CAAA;AAAA,SAC1C,MAAA,IAAW,KAAM,CAAA,SAAA,KAAc,SAAW,EAAA;AACxC,UAAO,MAAA,CAAA,IAAA,CAAK,MAAM,SAAS,CAAA;AAAA;AAC7B,OACD,CAAA;AAAA;AAEH,IAAO,OAAA,MAAA;AAAA,GACT;AAEA,EAAM,MAAA,UAAA,GAAa,YAAY,MAAM;AACnC,IAAA,OAAO,UACH,OACA,GAAA;AAAA,MACE,QAAQ,EAAK,GAAA,WAAA;AAAA;AAAA,MACb,IAAM,EAAA,EAAA;AAAA,MACN,KAAO,EAAA,EAAA;AAAA,MACP,GAAK,EAAA;AAAA,KACP;AAAA,GACH,EAAA,CAAC,WAAa,EAAA,OAAO,CAAC,CAAA;AAGzB,EAAM,MAAA,mBAAA,GAAsB,CAAC,KAAkB,KAAA;AAC7C,IAAM,MAAA,eAAA,GAAkB,gBAAiB,CAAA,YAAA,EAAc,KAAK,CAAA;AAC5D,IAAA,eAAA,CAAgB,eAAe,CAAA;AAAA,GACjC;AAGA,EAAM,MAAA,yBAAA,GAA4B,YAAY,MAAM;AAElD,IAAM,MAAA,sBAAA,GAA8B,eAAgB,CAAA,SAAA,EAAW,QAAQ,CAAA;AAEvE,IAAM,MAAA,cAAA,GAAiB,CAAC,KAUlB,KAAA;AACJ,MAAA,MAAM,WAAc,GAAA,CAAC,GACnB,KAAA,GAAA,KAAQ,SAAY,GAAM,GAAA,EAAA;AAC5B,MAAI,IAAA,KAAA,CAAM,cAAc,SAAW,EAAA;AACjC,QAAO,OAAA,IAAA;AAAA,OACT,MAAA,IACE,MAAM,SAAc,KAAA,OAAA,KACnB,MAAM,IAAS,KAAA,MAAA,IACd,MAAM,IAAS,KAAA,MAAA,IACf,MAAM,OAAY,KAAA,MAAA,IAClB,MAAM,GAAQ,KAAA,MAAA,IACd,MAAM,GAAQ,KAAA,MAAA,IACd,KAAM,CAAA,IAAA,KAAS,IACjB,CAAA,EAAA;AACA,QAAO,OAAA,IAAA,CAAK,aAAc,CAAA,QAAA,CAAS,iBAAmB,EAAA;AAAA,UACpD,EAAI,EAAA,IAAA;AAAA,UACJ,GAAA,EAAK,YAAY,KAAM,CAAA,IAAA,KAAS,SAAY,KAAM,CAAA,IAAA,GAAO,MAAM,IAAI,CAAA;AAAA,UACnE,GAAA,EAAK,YAAY,KAAM,CAAA,IAAA,KAAS,SAAY,KAAM,CAAA,IAAA,GAAO,MAAM,IAAI,CAAA;AAAA,UACnE,MAAQ,EAAA,WAAA;AAAA,YACN,KAAM,CAAA,OAAA,KAAY,MAAY,GAAA,KAAA,CAAM,UAAU,KAAM,CAAA;AAAA,WACtD;AAAA,UACA,EAAA,EAAI,YAAY,KAAM,CAAA,GAAA,KAAQ,SAAY,KAAM,CAAA,GAAA,GAAM,MAAM,IAAI,CAAA;AAAA,UAChE,EAAA,EAAI,YAAY,KAAM,CAAA,GAAA,KAAQ,SAAY,KAAM,CAAA,GAAA,GAAM,MAAM,IAAI,CAAA;AAAA,UAChE,KAAO,EAAA,IAAA,CAAK,aAAc,CAAA,QAAA,CAAS,KAAO,EAAA;AAAA,YACxC,KAAA,EAAO,cAAe,CAAA,KAAA,CAAM,KAAK;AAAA,WAClC;AAAA,SACF,CAAA;AAAA;AAIH,MAAM,MAAA,IAAA,GAAO,KAAM,CAAA,OAAA,CAAQ,KAAM,CAAA,CAAC,IAAI,KAAM,CAAA,CAAA,CAAE,CAAC,CAAA,GAAI,KAAM,CAAA,CAAA;AACzD,MAAA,IAAI,QAAQ,KAAM,CAAA,KAAA;AAWlB,MACG,IAAA,CAAA,KAAA,CAAM,cAAc,OAAW,IAAA,KAAA,CAAM,cAAc,SACpD,KAAA,KAAA,CAAM,UAAU,EAChB,EAAA;AACA,QAAA,KAAA,GAAQ,eAAe,OAAO,CAAA;AAAA;AAEhC,MAAA,OAAO,IAAS,KAAA,IAAA,GACZ,IAAK,CAAA,aAAA,CAAc,SAAS,UAAY,EAAA;AAAA,QACtC,KAAO,EAAA,IAAA;AAAA,QACP,KAAO,EAAA,IAAA,CAAK,aAAc,CAAA,QAAA,CAAS,KAAO,EAAA;AAAA,UACxC,KAAA,EAAO,eAAe,KAAK;AAAA,SAC5B;AAAA,OACF,CAAA,GACD,IAAK,CAAA,aAAA,CAAc,SAAS,WAAW,CAAA;AAAA,KAC7C;AAEA,IACE,uBAAA,KAAA,CAAA,aAAA;AAAA,MAAC,sBAAA;AAAA,MAAA;AAAA,QACC,eAAgB,EAAA,GAAA;AAAA,QAChB,QAAQ,CAAC,EAAE,KAAM,EAAA,KAAW,eAAe,KAAK,CAAA;AAAA,QAChD,mBAAmB,EAAA,IAAA;AAAA,QACnB,gBAAiB,EAAA,GAAA;AAAA,QACjB,gBAAgB,UAAW;AAAA;AAAA,KAC7B;AAAA,GAED,EAAA,CAAC,UAAY,EAAA,IAAI,CAAC,CAAA;AAGrB,EAAA,MAAM,YAAY,MAAM;AACtB,IAAA,MAAM,SAAS,0BAA2B,CAAA;AAAA,MACxC,YAAY,aAAc,EAAA;AAAA,MAC1B,QAAU,EAAA,CAAA,KAAA,KAAS,cAAe,CAAA,YAAA,EAAc,KAAK,CAAA;AAAA,MACrD,UAAA,EAAY,GAAG,IAAI,CAAA,OAAA,CAAA;AAAA,MACnB,aAAe,EAAA,CAAA,KAAA,KAAS,mBAAoB,CAAA,KAAA,CAAM,KAAK;AAAA,KACxD,CAAA;AACD,IAAO,OAAA,MAAA;AAAA,GACT;AAEA,EAAA,MAAM,YAAY,MAAM;AACtB,IAAA,OAAO,UAAa,GAAA,WAAA;AAAA,GACtB;AAEA,EAAA,MAAM,YAAY,MAAM;AACtB,IACE,uBAAA,KAAA,CAAA,aAAA;AAAA,MAAC,WAAA;AAAA,MAAA;AAAA,QACC,IAAA,EAAM,aAAc,CAAA,MAAA,EAAQ,YAAY,CAAA;AAAA,QACxC,MAAQ,EAAA,EAAA;AAAA,QACR,IAAA,EAAM,GAAG,IAAI,CAAA,OAAA,CAAA;AAAA,QACb,CAAG,EAAA;AAAA;AAAA,KACL;AAAA,GAEJ;AAEA,EAAM,MAAA,qBAAA,GAAwB,CAAC,KAAkB,KAAA;AAC/C,IAAA,IAAI,UAAU,WAAa,EAAA;AACzB,MAAA,cAAA,CAAe,KAAK,CAAA;AAAA;AACtB,GACF;AAEA,EAAM,MAAA,cAAA,GAAiB,YAAY,MAAM;AACvC,IAAA,MAAM,EAAE,WAAc,GAAA,CAAA,EAAM,GAAA,YAAA,CAAa,WAAW,EAAC;AAErD,IAAA,IAAI,gBAAgB,KAAO,EAAA;AACzB,MAAA,QAAA,CAAS,WAAW,CAAA;AAAA;AACtB,GACC,EAAA,CAAC,YAAc,EAAA,KAAK,CAAC,CAAA;AAExB,EAAM,MAAA,SAAA,GAAY,YAAY,MAAM;AAGlC,IAAA,MAAM,YAA2B,EAAC;AAClC,IAAI,IAAA,WAAA,IAAe,YAAY,MAAQ,EAAA;AACrC,MAAA,SAAA,CAAU,IAAK,CAAA;AAAA,QACb,SAAW,EAAA,SAAA;AAAA,QACX,IAAM,EAAA,WAAA;AAAA,QACN,UAAY,EAAA;AAAA,UACV,IAAM,EAAA,kBAAA;AAAA,YACJ,WAAA;AAAA,YACA,QAAS,CAAA,kBAAA;AAAA,YACT;AAAA,WACF;AAAA,UACA,MAAQ,EAAA;AAAA,YACN,IAAA,EAAM,WAAY,CAAA,iBAAA,CAAkB,CAAC,CAAA;AAAA,YACrC,IAAM,EAAA;AAAA,WACR;AAAA,UACA,OAAS,EAAA,IAAA,CAAK,aAAc,CAAA,QAAA,CAAS,OAAO;AAAA,SAC9C;AAAA,QACA,KAAO,EAAA;AAAA,UACL,IAAM,EAAA;AAAA,YACJ,GAAG,WAAY,CAAA,OAAA;AAAA,YACf,MAAA,EAAQ,WAAY,CAAA,iBAAA,CAAkB,CAAC;AAAA;AACzC;AACF,OACD,CAAA;AAAA;AAEH,IAAI,IAAA,SAAA,IAAa,UAAU,MAAQ,EAAA;AACjC,MAAA,SAAA,CAAU,IAAK,CAAA;AAAA,QACb,SAAW,EAAA,OAAA;AAAA,QACX,IAAM,EAAA,SAAA;AAAA,QACN,UAAY,EAAA;AAAA,UACV,IAAM,EAAA,kBAAA,CAAmB,SAAW,EAAA,QAAA,CAAS,kBAAkB,IAAI,CAAA;AAAA,UACnE,MAAQ,EAAA;AAAA,YACN,IAAA,EAAM,WAAY,CAAA,eAAA,CAAgB,CAAC,CAAA;AAAA,YACnC,IAAM,EAAA;AAAA,WACR;AAAA,UACA,OAAS,EAAA,IAAA,CAAK,aAAc,CAAA,QAAA,CAAS,KAAK;AAAA,SAC5C;AAAA,QACA,KAAO,EAAA;AAAA,UACL,IAAM,EAAA;AAAA,YACJ,GAAG,WAAY,CAAA,KAAA;AAAA,YACf,MAAA,EAAQ,WAAY,CAAA,eAAA,CAAgB,CAAC;AAAA;AACvC;AACF,OACD,CAAA;AAAA;AAEH,IAAI,IAAA,SAAA,IAAa,UAAU,MAAQ,EAAA;AACjC,MAAA,MAAM,cAAqB,EAAC;AAC5B,MAAU,SAAA,CAAA,GAAA,CAAI,CAAC,KAAe,KAAA;AAC5B,QAAI,IAAA,KAAA,CAAM,CAAE,CAAA,KAAA,CAAM,CAAC,GAAA,EAAU,EAAS,EAAA,GAAA,KAAe,GAAQ,KAAA,GAAA,CAAI,CAAC,CAAC,CAAG,EAAA;AACpE,UAAA,WAAA,CAAY,IAAK,CAAA;AAAA,YACf,GAAG,KAAA;AAAA,YACH,IAAA,EAAM,KAAM,CAAA,CAAA,CAAE,CAAC,CAAA;AAAA,YACf,CAAA,EAAG,CAAC,IAAI;AAAA,WACT,CAAA;AAAA,SACI,MAAA;AACL,UAAA,WAAA,CAAY,KAAK,KAAK,CAAA;AAAA;AACxB,OACD,CAAA;AACD,MAAA,SAAA,CAAU,IAAK,CAAA;AAAA,QACb,SAAW,EAAA,OAAA;AAAA,QACX,IAAM,EAAA,WAAA;AAAA,QACN,UAAY,EAAA;AAAA,UACV,IAAM,EAAA,kBAAA,CAAmB,SAAW,EAAA,QAAA,CAAS,WAAW,CAAA;AAAA,UACxD,MAAQ,EAAA;AAAA,YACN,IAAA,EAAM,WAAY,CAAA,eAAA,CAAgB,CAAC,CAAA;AAAA,YACnC,IAAM,EAAA;AAAA,WACR;AAAA,UACA,OAAS,EAAA,IAAA,CAAK,aAAc,CAAA,QAAA,CAAS,KAAK;AAAA,SAC5C;AAAA,QACA,KAAO,EAAA;AAAA,UACL,MAAQ,EAAA;AAAA,YACN,MAAA,EAAQ,WAAY,CAAA,eAAA,CAAgB,CAAC;AAAA,WACvC;AAAA,UACA,EAAI,EAAA;AAAA,YACF,IAAA,EAAM,WAAY,CAAA,eAAA,CAAgB,CAAC;AAAA,WACrC;AAAA,UACA,EAAI,EAAA;AAAA,YACF,IAAA,EAAM,WAAY,CAAA,eAAA,CAAgB,CAAC;AAAA;AACrC;AACF,OACD,CAAA;AAGD,MAAA,MAAM,cAAqB,EAAC;AAC5B,MAAU,SAAA,CAAA,GAAA,CAAI,CAAC,KAAe,KAAA;AAC5B,QAAI,IAAA,KAAA,CAAM,CAAE,CAAA,KAAA,CAAM,CAAC,GAAA,EAAU,EAAS,EAAA,GAAA,KAAe,GAAQ,KAAA,GAAA,CAAI,CAAC,CAAC,CAAG,EAAA;AACpE,UAAA,WAAA,CAAY,IAAK,CAAA;AAAA,YACf,GAAG,KAAA;AAAA,YACH,CAAA,EAAG,KAAM,CAAA,CAAA,CAAE,CAAC;AAAA,WACb,CAAA;AAAA,SACI,MAAA;AACL,UAAA,WAAA,CAAY,IAAK,CAAA;AAAA,YACf,GAAG,KAAA;AAAA,YACH,CAAG,EAAA;AAAA,WACJ,CAAA;AAAA;AACH,OACD,CAAA;AACD,MAAA,SAAA,CAAU,IAAK,CAAA;AAAA,QACb,SAAW,EAAA,SAAA;AAAA,QACX,IAAM,EAAA,WAAA;AAAA,QACN,KAAO,EAAA;AAAA,UACL,MAAM,EAAE,IAAA,EAAM,WAAY,CAAA,eAAA,CAAgB,CAAC,CAAE;AAAA;AAC/C,OACD,CAAA;AAAA;AAEH,IAAA,SAAA,CAAU,SAAS,CAAA;AACnB,IAAA,yBAAA,CAA0B,2BAA2B,CAAA;AACrD,IAAgB,eAAA,iBAAA,IAAI,KAAK,CAAA;AAAA,KACxB,CAAC,yBAAA,EAA2B,MAAM,SAAW,EAAA,WAAA,EAAa,SAAS,CAAC,CAAA;AAEvE,EAAA,OAAA,CAAQ,MAAM;AACZ,IAAU,SAAA,EAAA;AAAA,GACZ,EAAG,CAAC,SAAS,CAAC,CAAA;AAEd,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,MAAM,SAAY,GAAA,iBAAA,CAAkB,YAAa,CAAA,OAAA,EAAS,cAAc,CAAA;AACxE,IAAA,OAAO,MAAM;AACX,MAAA,IAAI,SAAW,EAAA;AACb,QAAU,SAAA,EAAA;AAAA;AACZ,KACF;AAAA,GACC,EAAA,CAAC,YAAc,EAAA,cAAc,CAAC,CAAA;AAEjC,EAAA,MAAM,cAAc,SAAU,EAAA;AAE9B,EAAA,uBACG,KAAA,CAAA,aAAA,CAAA,KAAA,EAAA,EAAI,SAAW,EAAA,OAAA,CAAQ,aAAe,EAAA,GAAA,EAAK,YAC1C,EAAA,kBAAA,KAAA,CAAA,aAAA,CAAC,KAAI,EAAA,EAAA,KAAA,EAAO,EAAE,MAAA,EAAQ,aACpB,EAAA,kBAAA,KAAA,CAAA,aAAA;AAAA,IAAC,KAAA;AAAA,IAAA;AAAA,MACC,GAAA,EAAK,SAAS,IAAI,CAAA,CAAA;AAAA,MAClB,oBAAoB,cAAe,EAAA;AAAA,MACnC,MAAQ,EAAA,SAAA,CAAU,MAAQ,EAAA,YAAA,EAAc,CAAC,CAAA;AAAA,MACzC,eAAe,EAAE,CAAA,EAAG,CAAC,EAAA,EAAI,EAAE,CAAE,EAAA;AAAA,MAC7B,QAAQ,SAAU,EAAA;AAAA,MAClB,MAAQ,EAAA,WAAA;AAAA,MACR,eAAiB,EAAA,qBAAA;AAAA,MACjB,iBAAiB,SAAU,EAAA;AAAA,MAC3B,cAAe,EAAA,QAAA;AAAA,MACf,IAAA;AAAA,MACA,SAAS,UAAW,EAAA;AAAA,MACpB,KAAA;AAAA,MAEA,YAAY,eAAgB,CAAA;AAAA,KAAA;AAAA,oBAE5B,KAAA,CAAA,aAAA,CAAC,SAAU,EAAA,EAAA,eAAA,EAAe,IAAC,EAAA,CAAA;AAAA,oBAC1B,KAAA,CAAA,aAAA,CAAA,SAAA,EAAA,EAAU,aAAa,EAAA,IAAA,EAAC,UAAQ,IAAC,EAAA,CAAA;AAAA,IACjC,eAAgB,EAAA;AAAA,IAChB,aAAc,EAAA;AAAA,IACd,eAAgB,EAAA;AAAA,IAChB,aAAc;AAAA,GAEnB,CACF,CAAA;AAEJ;;;;"}
|