|
@@ -4,43 +4,77 @@ import ParentSize from "@visx/responsive/lib/components/ParentSize";
|
|
|
|
|
|
|
|
import api from "shared/api";
|
|
import api from "shared/api";
|
|
|
import { Context } from "shared/Context";
|
|
import { Context } from "shared/Context";
|
|
|
-import { ChartType } from "shared/types";
|
|
|
|
|
|
|
+import { ChartType, StorageType } from "shared/types";
|
|
|
|
|
|
|
|
import TabSelector from "components/TabSelector";
|
|
import TabSelector from "components/TabSelector";
|
|
|
-import AreaChart from "./AreaChart";
|
|
|
|
|
|
|
+import AreaChart, { MetricsData } from "./AreaChart";
|
|
|
|
|
|
|
|
type PropsType = {
|
|
type PropsType = {
|
|
|
currentChart: ChartType;
|
|
currentChart: ChartType;
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
type StateType = {
|
|
type StateType = {
|
|
|
|
|
+ controllers: any[];
|
|
|
|
|
+ selectedController: any;
|
|
|
|
|
+ pods: string[];
|
|
|
|
|
+ selectedPod: string;
|
|
|
selectedRange: string;
|
|
selectedRange: string;
|
|
|
|
|
+ selectedMetric: string;
|
|
|
selectedMetricLabel: string;
|
|
selectedMetricLabel: string;
|
|
|
|
|
+ controllerDropdownExpanded: boolean;
|
|
|
|
|
+ podDropdownExpanded: boolean;
|
|
|
dropdownExpanded: boolean;
|
|
dropdownExpanded: boolean;
|
|
|
|
|
+ data: MetricsData[];
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
-var fakeData = [{
|
|
|
|
|
- date: 1613512500,
|
|
|
|
|
- value: 0.00017923172010701633,
|
|
|
|
|
-},
|
|
|
|
|
-{
|
|
|
|
|
- date: 1613513100,
|
|
|
|
|
- value: 0.00018,
|
|
|
|
|
-},
|
|
|
|
|
-{
|
|
|
|
|
- date: 1613513700,
|
|
|
|
|
- value: 0.0001923,
|
|
|
|
|
-}]
|
|
|
|
|
-
|
|
|
|
|
-export default class ListSection extends Component<PropsType, StateType> {
|
|
|
|
|
|
|
+type MetricsCPUDataResponse = {
|
|
|
|
|
+ pod?: string,
|
|
|
|
|
+ results: {
|
|
|
|
|
+ date: number,
|
|
|
|
|
+ cpu: string,
|
|
|
|
|
+ }[],
|
|
|
|
|
+}[]
|
|
|
|
|
+
|
|
|
|
|
+type MetricsMemoryDataResponse = {
|
|
|
|
|
+ pod?: string,
|
|
|
|
|
+ results: {
|
|
|
|
|
+ date: number,
|
|
|
|
|
+ memory: string,
|
|
|
|
|
+ }[],
|
|
|
|
|
+}[]
|
|
|
|
|
+
|
|
|
|
|
+const resolutions : { [range: string]: string } = {
|
|
|
|
|
+ "1H": "15s",
|
|
|
|
|
+ "6H": "15s",
|
|
|
|
|
+ "1D": "15s",
|
|
|
|
|
+ "1M": "5h",
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+const secondsBeforeNow : { [range: string]: number } = {
|
|
|
|
|
+ "1H": 60 * 60,
|
|
|
|
|
+ "6H": 60 * 60 * 6,
|
|
|
|
|
+ "1D": 60 * 60 * 24,
|
|
|
|
|
+ "1M": 60 * 60 * 24 * 30,
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+export default class MetricsSection extends Component<PropsType, StateType> {
|
|
|
state = {
|
|
state = {
|
|
|
|
|
+ pods: [] as string[],
|
|
|
|
|
+ selectedPod: "",
|
|
|
|
|
+ controllers: [] as any[],
|
|
|
|
|
+ selectedController: null as any,
|
|
|
selectedRange: "1H",
|
|
selectedRange: "1H",
|
|
|
- selectedMetricLabel: "CPU Utilization",
|
|
|
|
|
|
|
+ selectedMetric: "cpu",
|
|
|
|
|
+ selectedMetricLabel: "CPU Utilization (vCPUs)",
|
|
|
dropdownExpanded: false,
|
|
dropdownExpanded: false,
|
|
|
|
|
+ podDropdownExpanded: false,
|
|
|
|
|
+ controllerDropdownExpanded: false,
|
|
|
|
|
+ data: [] as MetricsData[],
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
componentDidMount() {
|
|
componentDidMount() {
|
|
|
- const { selectors, currentChart } = this.props;
|
|
|
|
|
|
|
+ // get all controllers and read in a list of pods
|
|
|
|
|
+ let { currentChart } = this.props;
|
|
|
let { currentCluster, currentProject, setCurrentError } = this.context;
|
|
let { currentCluster, currentProject, setCurrentError } = this.context;
|
|
|
|
|
|
|
|
api
|
|
api
|
|
@@ -58,11 +92,161 @@ export default class ListSection extends Component<PropsType, StateType> {
|
|
|
}
|
|
}
|
|
|
)
|
|
)
|
|
|
.then((res) => {
|
|
.then((res) => {
|
|
|
- this.setState({ controllers: res.data, loading: false });
|
|
|
|
|
|
|
+ // TODO -- check at least one controller returned
|
|
|
|
|
+
|
|
|
|
|
+ // iterate through the controllers to get the list of pods
|
|
|
|
|
+ this.setState({ controllers: res.data, selectedController: res.data[0] });
|
|
|
|
|
+
|
|
|
|
|
+ this.getPods()
|
|
|
})
|
|
})
|
|
|
.catch((err) => {
|
|
.catch((err) => {
|
|
|
setCurrentError(JSON.stringify(err));
|
|
setCurrentError(JSON.stringify(err));
|
|
|
- this.setState({ controllers: [], loading: false });
|
|
|
|
|
|
|
+ this.setState({ controllers: [] });
|
|
|
|
|
+ });
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ componentDidUpdate(prevProps: PropsType, prevState: StateType) {
|
|
|
|
|
+ // if resolution, data kind, controllers, or pods have changed, update data
|
|
|
|
|
+ if (this.state.selectedMetric != prevState.selectedMetric) {
|
|
|
|
|
+ this.getMetrics()
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (this.state.selectedRange != prevState.selectedRange) {
|
|
|
|
|
+ this.getMetrics()
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (this.state.selectedPod != prevState.selectedPod) {
|
|
|
|
|
+ this.getMetrics()
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (this.state.selectedController?.metadata?.name != prevState.selectedController?.metadata?.name) {
|
|
|
|
|
+ this.getMetrics()
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ getMetrics = () => {
|
|
|
|
|
+ if (this.state.pods.length == 0) {
|
|
|
|
|
+ return
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ let { currentChart } = this.props;
|
|
|
|
|
+ let { currentCluster, currentProject, setCurrentError } = this.context;
|
|
|
|
|
+ let kind = this.state.selectedMetric
|
|
|
|
|
+ let shouldsum = true
|
|
|
|
|
+
|
|
|
|
|
+ // calculate start and end range
|
|
|
|
|
+ var d = new Date();
|
|
|
|
|
+ var end = Math.round(d.getTime() / 1000);
|
|
|
|
|
+ var start = end - secondsBeforeNow[this.state.selectedRange]
|
|
|
|
|
+
|
|
|
|
|
+ let pods = this.state.pods
|
|
|
|
|
+
|
|
|
|
|
+ if (this.state.selectedPod != "All") {
|
|
|
|
|
+ pods = [this.state.selectedPod]
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ api
|
|
|
|
|
+ .getMetrics(
|
|
|
|
|
+ "<token>",
|
|
|
|
|
+ {
|
|
|
|
|
+ cluster_id: currentCluster.id,
|
|
|
|
|
+ metric: kind,
|
|
|
|
|
+ shouldsum: shouldsum,
|
|
|
|
|
+ pods: pods,
|
|
|
|
|
+ namespace: currentChart.namespace,
|
|
|
|
|
+ startrange: start,
|
|
|
|
|
+ endrange: end,
|
|
|
|
|
+ resolution: resolutions[this.state.selectedRange],
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ id: currentProject.id,
|
|
|
|
|
+ }
|
|
|
|
|
+ )
|
|
|
|
|
+ .then((res) => {
|
|
|
|
|
+ // transform the metrics to expected form
|
|
|
|
|
+ if (kind == "cpu") {
|
|
|
|
|
+ let data = res.data as MetricsCPUDataResponse
|
|
|
|
|
+
|
|
|
|
|
+ // if summed, just look at the first data
|
|
|
|
|
+ let tData = data[0].results.map(
|
|
|
|
|
+ (d: {
|
|
|
|
|
+ date: number,
|
|
|
|
|
+ cpu: string,
|
|
|
|
|
+ }, i: number) => {
|
|
|
|
|
+ return {
|
|
|
|
|
+ date: d.date,
|
|
|
|
|
+ value: parseFloat(d.cpu),
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ )
|
|
|
|
|
+
|
|
|
|
|
+ this.setState({ data: tData })
|
|
|
|
|
+ } else if (kind == "memory") {
|
|
|
|
|
+ let data = res.data as MetricsMemoryDataResponse
|
|
|
|
|
+
|
|
|
|
|
+ let tData = data[0].results.map(
|
|
|
|
|
+ (d: {
|
|
|
|
|
+ date: number,
|
|
|
|
|
+ memory: string,
|
|
|
|
|
+ }, i: number) => {
|
|
|
|
|
+ return {
|
|
|
|
|
+ date: d.date,
|
|
|
|
|
+ value: parseFloat(d.memory) / (1024 * 1024), // put units in Mi
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ )
|
|
|
|
|
+
|
|
|
|
|
+ this.setState({ data: tData })
|
|
|
|
|
+ }
|
|
|
|
|
+ })
|
|
|
|
|
+ .catch((err) => {
|
|
|
|
|
+ setCurrentError(JSON.stringify(err));
|
|
|
|
|
+ // this.setState({ controllers: [], loading: false });
|
|
|
|
|
+ });
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ getPods = () => {
|
|
|
|
|
+ let { selectedController } = this.state;
|
|
|
|
|
+ let { currentCluster, currentProject, setCurrentError } = this.context;
|
|
|
|
|
+
|
|
|
|
|
+ let selectors = [] as string[];
|
|
|
|
|
+ let ml =
|
|
|
|
|
+ selectedController?.spec?.selector?.matchLabels || selectedController?.spec?.selector;
|
|
|
|
|
+ let i = 1;
|
|
|
|
|
+ let selector = "";
|
|
|
|
|
+ for (var key in ml) {
|
|
|
|
|
+ selector += key + "=" + ml[key];
|
|
|
|
|
+ if (i != Object.keys(ml).length) {
|
|
|
|
|
+ selector += ",";
|
|
|
|
|
+ }
|
|
|
|
|
+ i += 1;
|
|
|
|
|
+ }
|
|
|
|
|
+ selectors.push(selector);
|
|
|
|
|
+
|
|
|
|
|
+ api
|
|
|
|
|
+ .getMatchingPods(
|
|
|
|
|
+ "<token>",
|
|
|
|
|
+ {
|
|
|
|
|
+ cluster_id: currentCluster.id,
|
|
|
|
|
+ selectors,
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ id: currentProject.id,
|
|
|
|
|
+ }
|
|
|
|
|
+ )
|
|
|
|
|
+ .then((res) => {
|
|
|
|
|
+ let pods = res?.data?.map((pod: any) => {
|
|
|
|
|
+ return pod?.metadata?.name
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ this.setState({ pods, selectedPod: "All" });
|
|
|
|
|
+
|
|
|
|
|
+ this.getMetrics()
|
|
|
|
|
+ })
|
|
|
|
|
+ .catch((err) => {
|
|
|
|
|
+ console.log(err);
|
|
|
|
|
+ setCurrentError(JSON.stringify(err));
|
|
|
|
|
+ return;
|
|
|
});
|
|
});
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -85,18 +269,105 @@ export default class ListSection extends Component<PropsType, StateType> {
|
|
|
}
|
|
}
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
|
|
+ renderPodDropdown = () => {
|
|
|
|
|
+ if (this.state.podDropdownExpanded) {
|
|
|
|
|
+ return (
|
|
|
|
|
+ <>
|
|
|
|
|
+ <DropdownOverlay
|
|
|
|
|
+ onClick={() => this.setState({ podDropdownExpanded: false })}
|
|
|
|
|
+ />
|
|
|
|
|
+ <Dropdown
|
|
|
|
|
+ dropdownWidth="400px"
|
|
|
|
|
+ dropdownMaxHeight="200px"
|
|
|
|
|
+ onClick={() => this.setState({ podDropdownExpanded: false })}
|
|
|
|
|
+ >
|
|
|
|
|
+ {this.renderPodOptionList()}
|
|
|
|
|
+ </Dropdown>
|
|
|
|
|
+ </>
|
|
|
|
|
+ );
|
|
|
|
|
+ }
|
|
|
|
|
+ };
|
|
|
|
|
+
|
|
|
|
|
+ renderPodOptionList = () => {
|
|
|
|
|
+ let allPod = [(
|
|
|
|
|
+ <Option
|
|
|
|
|
+ key={0}
|
|
|
|
|
+ selected={"All" === this.state.selectedPod}
|
|
|
|
|
+ onClick={() => this.setState({ selectedPod: "All" })}
|
|
|
|
|
+ lastItem={false}
|
|
|
|
|
+ >
|
|
|
|
|
+ All (summed)
|
|
|
|
|
+ </Option>
|
|
|
|
|
+ )];
|
|
|
|
|
+
|
|
|
|
|
+ let podOptions = this.state.pods.map(
|
|
|
|
|
+ (option: string, i: number) => {
|
|
|
|
|
+ return (
|
|
|
|
|
+ <Option
|
|
|
|
|
+ key={i + 1}
|
|
|
|
|
+ selected={option === this.state.selectedPod}
|
|
|
|
|
+ onClick={() => this.setState({ selectedPod: option })}
|
|
|
|
|
+ lastItem={i === this.state.pods.length - 1}
|
|
|
|
|
+ >
|
|
|
|
|
+ {option}
|
|
|
|
|
+ </Option>
|
|
|
|
|
+ );
|
|
|
|
|
+ }
|
|
|
|
|
+ )
|
|
|
|
|
+
|
|
|
|
|
+ return allPod.concat(podOptions)
|
|
|
|
|
+ };
|
|
|
|
|
+
|
|
|
|
|
+ renderControllerDropdown = () => {
|
|
|
|
|
+ if (this.state.controllerDropdownExpanded) {
|
|
|
|
|
+ return (
|
|
|
|
|
+ <>
|
|
|
|
|
+ <DropdownOverlay
|
|
|
|
|
+ onClick={() => this.setState({ controllerDropdownExpanded: false })}
|
|
|
|
|
+ />
|
|
|
|
|
+ <Dropdown
|
|
|
|
|
+ dropdownWidth="300px"
|
|
|
|
|
+ dropdownMaxHeight="200px"
|
|
|
|
|
+ onClick={() => this.setState({ controllerDropdownExpanded: false })}
|
|
|
|
|
+ >
|
|
|
|
|
+ {this.renderControllerOptionList()}
|
|
|
|
|
+ </Dropdown>
|
|
|
|
|
+ </>
|
|
|
|
|
+ );
|
|
|
|
|
+ }
|
|
|
|
|
+ };
|
|
|
|
|
+
|
|
|
|
|
+ renderControllerOptionList = () => {
|
|
|
|
|
+ return this.state.controllers.map(
|
|
|
|
|
+ (controller: any, i: number) => {
|
|
|
|
|
+ let name = controller?.metadata?.name
|
|
|
|
|
+
|
|
|
|
|
+ return (
|
|
|
|
|
+ <Option
|
|
|
|
|
+ key={i}
|
|
|
|
|
+ selected={name === this.state.selectedController?.metadata?.name}
|
|
|
|
|
+ onClick={() => this.setState({ selectedController: controller })}
|
|
|
|
|
+ lastItem={i === this.state.controllers.length - 1}
|
|
|
|
|
+ >
|
|
|
|
|
+ {name}
|
|
|
|
|
+ </Option>
|
|
|
|
|
+ );
|
|
|
|
|
+ }
|
|
|
|
|
+ )
|
|
|
|
|
+ };
|
|
|
|
|
+
|
|
|
renderOptionList = () => {
|
|
renderOptionList = () => {
|
|
|
let metricOptions = [
|
|
let metricOptions = [
|
|
|
- { value: "cpu", label: "CPU Utilization" },
|
|
|
|
|
- { value: "ram", label: "RAM Utilization" },
|
|
|
|
|
|
|
+ { value: "cpu", label: "CPU Utilization (vCPUs)" },
|
|
|
|
|
+ { value: "memory", label: "RAM Utilization (Mi)" },
|
|
|
];
|
|
];
|
|
|
return metricOptions.map(
|
|
return metricOptions.map(
|
|
|
(option: { value: string; label: string }, i: number) => {
|
|
(option: { value: string; label: string }, i: number) => {
|
|
|
return (
|
|
return (
|
|
|
<Option
|
|
<Option
|
|
|
key={i}
|
|
key={i}
|
|
|
- selected={option.label === this.state.selectedMetricLabel}
|
|
|
|
|
- onClick={() => this.setState({ selectedMetricLabel: option.label })}
|
|
|
|
|
|
|
+ selected={option.value === this.state.selectedMetric}
|
|
|
|
|
+ onClick={() => this.setState({ selectedMetric: option.value, selectedMetricLabel: option.label })}
|
|
|
lastItem={i === metricOptions.length - 1}
|
|
lastItem={i === metricOptions.length - 1}
|
|
|
>
|
|
>
|
|
|
{option.label}
|
|
{option.label}
|
|
@@ -110,7 +381,13 @@ export default class ListSection extends Component<PropsType, StateType> {
|
|
|
return (
|
|
return (
|
|
|
<StyledMetricsSection>
|
|
<StyledMetricsSection>
|
|
|
<ParentSize>
|
|
<ParentSize>
|
|
|
- {({ width, height }) => <AreaChart data={fakeData} width={width} height={height} />}
|
|
|
|
|
|
|
+ {({ width, height }) => <AreaChart
|
|
|
|
|
+ data={this.state.data}
|
|
|
|
|
+ width={width}
|
|
|
|
|
+ height={height}
|
|
|
|
|
+ resolution={this.state.selectedRange}
|
|
|
|
|
+ margin={{ top: 70, right: 0, bottom: 0, left: 50 }}
|
|
|
|
|
+ />}
|
|
|
</ParentSize>
|
|
</ParentSize>
|
|
|
<MetricSelector
|
|
<MetricSelector
|
|
|
onClick={() =>
|
|
onClick={() =>
|
|
@@ -121,15 +398,31 @@ export default class ListSection extends Component<PropsType, StateType> {
|
|
|
<i className="material-icons">arrow_drop_down</i>
|
|
<i className="material-icons">arrow_drop_down</i>
|
|
|
{this.renderDropdown()}
|
|
{this.renderDropdown()}
|
|
|
</MetricSelector>
|
|
</MetricSelector>
|
|
|
|
|
+ <ControllerSelector
|
|
|
|
|
+ onClick={() =>
|
|
|
|
|
+ this.setState({ controllerDropdownExpanded: !this.state.controllerDropdownExpanded })
|
|
|
|
|
+ }
|
|
|
|
|
+ >
|
|
|
|
|
+ {this.state.selectedController?.metadata?.name}
|
|
|
|
|
+ <i className="material-icons">arrow_drop_down</i>
|
|
|
|
|
+ {this.renderControllerDropdown()}
|
|
|
|
|
+ </ControllerSelector>
|
|
|
|
|
+ <PodSelector
|
|
|
|
|
+ onClick={() =>
|
|
|
|
|
+ this.setState({ podDropdownExpanded: !this.state.podDropdownExpanded })
|
|
|
|
|
+ }
|
|
|
|
|
+ >
|
|
|
|
|
+ {this.state.selectedPod}
|
|
|
|
|
+ <i className="material-icons">arrow_drop_down</i>
|
|
|
|
|
+ {this.renderPodDropdown()}
|
|
|
|
|
+ </PodSelector>
|
|
|
<RangeWrapper>
|
|
<RangeWrapper>
|
|
|
<TabSelector
|
|
<TabSelector
|
|
|
options={[
|
|
options={[
|
|
|
{ value: "1H", label: "1H" },
|
|
{ value: "1H", label: "1H" },
|
|
|
|
|
+ { value: "6H", label: "6H" },
|
|
|
{ value: "1D", label: "1D" },
|
|
{ value: "1D", label: "1D" },
|
|
|
{ value: "1M", label: "1M" },
|
|
{ value: "1M", label: "1M" },
|
|
|
- { value: "3M", label: "3M" },
|
|
|
|
|
- { value: "1Y", label: "1Y" },
|
|
|
|
|
- { value: "ALL", label: "ALL" },
|
|
|
|
|
]}
|
|
]}
|
|
|
currentTab={this.state.selectedRange}
|
|
currentTab={this.state.selectedRange}
|
|
|
setCurrentTab={(x: string) => this.setState({ selectedRange: x })}
|
|
setCurrentTab={(x: string) => this.setState({ selectedRange: x })}
|
|
@@ -140,7 +433,7 @@ export default class ListSection extends Component<PropsType, StateType> {
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-ListSection.contextType = Context;
|
|
|
|
|
|
|
+MetricsSection.contextType = Context;
|
|
|
|
|
|
|
|
const DropdownOverlay = styled.div`
|
|
const DropdownOverlay = styled.div`
|
|
|
position: fixed;
|
|
position: fixed;
|
|
@@ -192,21 +485,22 @@ const Dropdown = styled.div`
|
|
|
box-shadow: 0 4px 8px 0px #00000088;
|
|
box-shadow: 0 4px 8px 0px #00000088;
|
|
|
`;
|
|
`;
|
|
|
|
|
|
|
|
|
|
+
|
|
|
const RangeWrapper = styled.div`
|
|
const RangeWrapper = styled.div`
|
|
|
position: absolute;
|
|
position: absolute;
|
|
|
- bottom: 10px;
|
|
|
|
|
- font-weight: bold;
|
|
|
|
|
|
|
+ top: 20px;
|
|
|
left: 0;
|
|
left: 0;
|
|
|
- width: 100%;
|
|
|
|
|
|
|
+ font-weight: bold;
|
|
|
|
|
+ width: calc(100% - 36px);
|
|
|
`;
|
|
`;
|
|
|
|
|
|
|
|
const MetricSelector = styled.div`
|
|
const MetricSelector = styled.div`
|
|
|
- font-size: 16px;
|
|
|
|
|
|
|
+ font-size: 13px;
|
|
|
font-weight: 500;
|
|
font-weight: 500;
|
|
|
color: #ffffff;
|
|
color: #ffffff;
|
|
|
position: absolute;
|
|
position: absolute;
|
|
|
top: 0;
|
|
top: 0;
|
|
|
- left: 5px;
|
|
|
|
|
|
|
+ left: 0;
|
|
|
display: flex;
|
|
display: flex;
|
|
|
align-items: center;
|
|
align-items: center;
|
|
|
cursor: pointer;
|
|
cursor: pointer;
|
|
@@ -224,6 +518,14 @@ const MetricSelector = styled.div`
|
|
|
}
|
|
}
|
|
|
`;
|
|
`;
|
|
|
|
|
|
|
|
|
|
+const ControllerSelector = styled(MetricSelector)`
|
|
|
|
|
+ left: 200px;
|
|
|
|
|
+`
|
|
|
|
|
+
|
|
|
|
|
+const PodSelector = styled(MetricSelector)`
|
|
|
|
|
+ left: 500px;
|
|
|
|
|
+`
|
|
|
|
|
+
|
|
|
const StyledMetricsSection = styled.div`
|
|
const StyledMetricsSection = styled.div`
|
|
|
width: 100%;
|
|
width: 100%;
|
|
|
height: 100%;
|
|
height: 100%;
|