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

some touchups

Signed-off-by: Thomas Evans <tevans3@icloud.com>
jjarrett21 2 лет назад
Родитель
Сommit
0678a3301a
3 измененных файлов с 206 добавлено и 177 удалено
  1. 1 1
      ui/src/CloudCost/CloudCost.js
  2. 1 1
      ui/src/CloudCostReports.js
  3. 204 175
      ui/src/Reports.js

+ 1 - 1
ui/src/CloudCost/CloudCost.js

@@ -155,7 +155,7 @@ const CloudCost = ({ cumulativeData, totalData, graphData, currency }) => {
                     >
                     >
                       {cell.id === "kubernetesPercent"
                       {cell.id === "kubernetesPercent"
                         ? round(totalData[cell.id] * 100, 2)
                         ? round(totalData[cell.id] * 100, 2)
-                        : totalData[cell.id]}
+                        : toCurrency(round(totalData[cell.id]), currency)}
                     </TableCell>
                     </TableCell>
                   );
                   );
                 })}
                 })}

+ 1 - 1
ui/src/CloudCostReports.js

@@ -162,7 +162,7 @@ const CloudCostReports = () => {
     if (!init) {
     if (!init) {
       initialize();
       initialize();
     }
     }
-    if (init && fetch) {
+    if (init || fetch) {
       fetchData();
       fetchData();
     }
     }
   }, [init, fetch]);
   }, [init, fetch]);

+ 204 - 175
ui/src/Reports.js

@@ -1,201 +1,230 @@
-import CircularProgress from '@material-ui/core/CircularProgress'
-import IconButton from '@material-ui/core/IconButton'
-import Paper from '@material-ui/core/Paper'
-import Typography from '@material-ui/core/Typography'
-import RefreshIcon from '@material-ui/icons/Refresh'
-import { makeStyles } from '@material-ui/styles'
-import { filter, find, forEach, get, isArray, sortBy, toArray, trim } from 'lodash'
-import React, { useEffect, useState } from 'react'
-import ReactDOM from 'react-dom'
-import { useLocation, useHistory } from 'react-router';
+import CircularProgress from "@material-ui/core/CircularProgress";
+import IconButton from "@material-ui/core/IconButton";
+import Paper from "@material-ui/core/Paper";
+import Typography from "@material-ui/core/Typography";
+import RefreshIcon from "@material-ui/icons/Refresh";
+import { makeStyles } from "@material-ui/styles";
+import {
+  filter,
+  find,
+  forEach,
+  get,
+  isArray,
+  sortBy,
+  toArray,
+  trim,
+} from "lodash";
+import React, { useEffect, useState } from "react";
+import ReactDOM from "react-dom";
+import { useLocation, useHistory } from "react-router";
 
 
-import AllocationReport from './components/AllocationReport';
-import Controls from './components/Controls';
-import Header from './components/Header';
-import Page from './components/Page';
-import Subtitle from './components/Subtitle';
-import Warnings from './components/Warnings';
-import AllocationService from './services/allocation';
-import { checkCustomWindow, cumulativeToTotals, rangeToCumulative, toVerboseTimeRange } from './util';
-import { currencyCodes } from './constants/currencyCodes'
+import AllocationReport from "./components/AllocationReport";
+import Controls from "./components/Controls";
+import Header from "./components/Header";
+import Page from "./components/Page";
+import Subtitle from "./components/Subtitle";
+import Warnings from "./components/Warnings";
+import AllocationService from "./services/allocation";
+import {
+  checkCustomWindow,
+  cumulativeToTotals,
+  rangeToCumulative,
+  toVerboseTimeRange,
+} from "./util";
+import { currencyCodes } from "./constants/currencyCodes";
 
 
 const windowOptions = [
 const windowOptions = [
-  { name: 'Today', value: 'today' },
-  { name: 'Yesterday', value: 'yesterday' },
-  { name: 'Week-to-date', value: 'week' },
-  { name: 'Month-to-date', value: 'month' },
-  { name: 'Last week', value: 'lastweek' },
-  { name: 'Last month', value: 'lastmonth' },
-  { name: 'Last 7 days', value: '6d' },
-  { name: 'Last 30 days', value: '29d' },
-  { name: 'Last 60 days', value: '59d' },
-  { name: 'Last 90 days', value: '89d' },
-]
+  { name: "Today", value: "today" },
+  { name: "Yesterday", value: "yesterday" },
+  { name: "Week-to-date", value: "week" },
+  { name: "Month-to-date", value: "month" },
+  { name: "Last week", value: "lastweek" },
+  { name: "Last month", value: "lastmonth" },
+  { name: "Last 7 days", value: "6d" },
+  { name: "Last 30 days", value: "29d" },
+  { name: "Last 60 days", value: "59d" },
+  { name: "Last 90 days", value: "89d" },
+];
 
 
 const aggregationOptions = [
 const aggregationOptions = [
-  { name: 'Cluster', value: 'cluster' },
-  { name: 'Node', value: 'node' },
-  { name: 'Namespace', value: 'namespace' },
-  { name: 'Controller kind', value: 'controllerKind' },
-  { name: 'Controller', value: 'controller' },
-  { name: 'Service', value: 'service' },
-  { name: 'Pod', value: 'pod' },
-  { name: 'Container', value: 'container' },
-]
+  { name: "Cluster", value: "cluster" },
+  { name: "Node", value: "node" },
+  { name: "Namespace", value: "namespace" },
+  { name: "Controller kind", value: "controllerKind" },
+  { name: "Controller", value: "controller" },
+  { name: "Service", value: "service" },
+  { name: "Pod", value: "pod" },
+  { name: "Container", value: "container" },
+];
 
 
 const accumulateOptions = [
 const accumulateOptions = [
-  { name: 'Entire window', value: true },
-  { name: 'Daily', value: false },
-]
+  { name: "Entire window", value: true },
+  { name: "Daily", value: false },
+];
 
 
 const useStyles = makeStyles({
 const useStyles = makeStyles({
   reportHeader: {
   reportHeader: {
-    display: 'flex',
-    flexFlow: 'row',
+    display: "flex",
+    flexFlow: "row",
     padding: 24,
     padding: 24,
   },
   },
   titles: {
   titles: {
     flexGrow: 1,
     flexGrow: 1,
   },
   },
-})
+});
 
 
 // generateTitle generates a string title from a report object
 // generateTitle generates a string title from a report object
 function generateTitle({ window, aggregateBy, accumulate }) {
 function generateTitle({ window, aggregateBy, accumulate }) {
-  let windowName = get(find(windowOptions, { value: window }), 'name', '')
-  if (windowName === '') {
+  let windowName = get(find(windowOptions, { value: window }), "name", "");
+  if (windowName === "") {
     if (checkCustomWindow(window)) {
     if (checkCustomWindow(window)) {
-      windowName = toVerboseTimeRange(window)
+      windowName = toVerboseTimeRange(window);
     } else {
     } else {
-      console.warn(`unknown window: ${window}`)
+      console.warn(`unknown window: ${window}`);
     }
     }
   }
   }
 
 
-  let aggregationName = get(find(aggregationOptions, { value: aggregateBy }), 'name', '').toLowerCase()
-  if (aggregationName === '') {
-    console.warn(`unknown aggregation: ${aggregateBy}`)
+  let aggregationName = get(
+    find(aggregationOptions, { value: aggregateBy }),
+    "name",
+    ""
+  ).toLowerCase();
+  if (aggregationName === "") {
+    console.warn(`unknown aggregation: ${aggregateBy}`);
   }
   }
 
 
-  let str = `${windowName} by ${aggregationName}`
+  let str = `${windowName} by ${aggregationName}`;
 
 
   if (!accumulate) {
   if (!accumulate) {
-    str = `${str} daily`
+    str = `${str} daily`;
   }
   }
 
 
-  return str
+  return str;
 }
 }
 
 
-
 const ReportsPage = () => {
 const ReportsPage = () => {
-  const classes = useStyles()
+  const classes = useStyles();
 
 
   // Allocation data state
   // Allocation data state
-  const [allocationData, setAllocationData] = useState([])
-  const [cumulativeData, setCumulativeData] = useState({})
-  const [totalData, setTotalData] = useState({})
+  const [allocationData, setAllocationData] = useState([]);
+  const [cumulativeData, setCumulativeData] = useState({});
+  const [totalData, setTotalData] = useState({});
 
 
   // When allocation data changes, create a cumulative version of it
   // When allocation data changes, create a cumulative version of it
   useEffect(() => {
   useEffect(() => {
-    const cumulative = rangeToCumulative(allocationData, aggregateBy)
-    setCumulativeData(toArray(cumulative))
-    setTotalData(cumulativeToTotals(cumulative))
-  }, [allocationData])
+    const cumulative = rangeToCumulative(allocationData, aggregateBy);
+    setCumulativeData(toArray(cumulative));
+    setTotalData(cumulativeToTotals(cumulative));
+  }, [allocationData]);
 
 
   // Form state, which controls form elements, but not the report itself. On
   // Form state, which controls form elements, but not the report itself. On
   // certain actions, the form state may flow into the report state.
   // certain actions, the form state may flow into the report state.
-  const [window, setWindow] = useState(windowOptions[0].value)
-  const [aggregateBy, setAggregateBy] = useState(aggregationOptions[0].value)
-  const [accumulate, setAccumulate] = useState(accumulateOptions[0].value)
-  const [currency, setCurrency] = useState('USD')
+  const [window, setWindow] = useState(windowOptions[0].value);
+  const [aggregateBy, setAggregateBy] = useState(aggregationOptions[0].value);
+  const [accumulate, setAccumulate] = useState(accumulateOptions[0].value);
+  const [currency, setCurrency] = useState("USD");
 
 
   // Report state, including current report and saved options
   // Report state, including current report and saved options
-  const [title, setTitle] = useState('Last 7 days by namespace daily')
+  const [title, setTitle] = useState("Last 7 days by namespace daily");
 
 
   // When parameters changes, fetch data. This should be the
   // When parameters changes, fetch data. This should be the
   // only mechanism used to fetch data. Also generate a sensible title from the paramters.
   // only mechanism used to fetch data. Also generate a sensible title from the paramters.
   useEffect(() => {
   useEffect(() => {
-    setFetch(true)
-    setTitle(generateTitle({ window, aggregateBy, accumulate }))
-  }, [window, aggregateBy, accumulate])
+    setFetch(true);
+    setTitle(generateTitle({ window, aggregateBy, accumulate }));
+  }, [window, aggregateBy, accumulate]);
 
 
   // page and settings state
   // page and settings state
-  const [init, setInit] = useState(false)
-  const [fetch, setFetch] = useState(false)
-  const [loading, setLoading] = useState(true)
-  const [errors, setErrors] = useState([])
+  const [init, setInit] = useState(false);
+  const [fetch, setFetch] = useState(false);
+  const [loading, setLoading] = useState(true);
+  const [errors, setErrors] = useState([]);
 
 
   // Initialize once, then fetch report each time setFetch(true) is called
   // Initialize once, then fetch report each time setFetch(true) is called
   useEffect(() => {
   useEffect(() => {
     if (!init) {
     if (!init) {
-      initialize()
+      initialize();
     }
     }
-    if (init && fetch) {
-      fetchData()
+    if (init || fetch) {
+      fetchData();
     }
     }
-  }, [init, fetch])
+  }, [init, fetch]);
 
 
   // parse any context information from the URL
   // parse any context information from the URL
   const routerLocation = useLocation();
   const routerLocation = useLocation();
   const searchParams = new URLSearchParams(routerLocation.search);
   const searchParams = new URLSearchParams(routerLocation.search);
   const routerHistory = useHistory();
   const routerHistory = useHistory();
   useEffect(() => {
   useEffect(() => {
-    setWindow(searchParams.get('window') || '6d');
-    setAggregateBy(searchParams.get('agg') || 'namespace');
-    setAccumulate((searchParams.get('acc') === 'true') || false);
-    setCurrency(searchParams.get('currency') || 'USD');
+    setWindow(searchParams.get("window") || "6d");
+    setAggregateBy(searchParams.get("agg") || "namespace");
+    setAccumulate(searchParams.get("acc") === "true" || false);
+    setCurrency(searchParams.get("currency") || "USD");
   }, [routerLocation]);
   }, [routerLocation]);
 
 
   async function initialize() {
   async function initialize() {
-    setInit(true)
+    setInit(true);
   }
   }
 
 
   async function fetchData() {
   async function fetchData() {
-    setLoading(true)
-    setErrors([])
+    setLoading(true);
+    setErrors([]);
 
 
     try {
     try {
-      const resp = await AllocationService.fetchAllocation(window, aggregateBy, { accumulate })
+      const resp = await AllocationService.fetchAllocation(
+        window,
+        aggregateBy,
+        { accumulate }
+      );
       if (resp.data && resp.data.length > 0) {
       if (resp.data && resp.data.length > 0) {
-        const allocationRange = resp.data
+        const allocationRange = resp.data;
         for (const i in allocationRange) {
         for (const i in allocationRange) {
           // update cluster aggregations to use clusterName/clusterId names
           // update cluster aggregations to use clusterName/clusterId names
-          allocationRange[i] = sortBy(allocationRange[i], a => a.totalCost)
+          allocationRange[i] = sortBy(allocationRange[i], (a) => a.totalCost);
         }
         }
-        setAllocationData(allocationRange)
+        setAllocationData(allocationRange);
       } else {
       } else {
-        if (resp.message && resp.message.indexOf('boundary error') >= 0) {
-          let match = resp.message.match(/(ETL is \d+\.\d+% complete)/)
-          let secondary = 'Try again after ETL build is complete'
+        if (resp.message && resp.message.indexOf("boundary error") >= 0) {
+          let match = resp.message.match(/(ETL is \d+\.\d+% complete)/);
+          let secondary = "Try again after ETL build is complete";
           if (match.length > 0) {
           if (match.length > 0) {
-            secondary = `${match[1]}. ${secondary}`
+            secondary = `${match[1]}. ${secondary}`;
           }
           }
-          setErrors([{
-            primary: 'Data unavailable while ETL is building',
-            secondary: secondary,
-          }])
+          setErrors([
+            {
+              primary: "Data unavailable while ETL is building",
+              secondary: secondary,
+            },
+          ]);
         }
         }
-        setAllocationData([])
+        setAllocationData([]);
       }
       }
     } catch (err) {
     } catch (err) {
-      if (err.message.indexOf('404') === 0) {
-        setErrors([{
-          primary: 'Failed to load report data',
-          secondary: 'Please update Kubecost to the latest version, then contact support if problems persist.'
-        }])
+      if (err.message.indexOf("404") === 0) {
+        setErrors([
+          {
+            primary: "Failed to load report data",
+            secondary:
+              "Please update Kubecost to the latest version, then contact support if problems persist.",
+          },
+        ]);
       } else {
       } else {
-        let secondary = 'Please contact Kubecost support with a bug report if problems persist.'
+        let secondary =
+          "Please contact Kubecost support with a bug report if problems persist.";
         if (err.message.length > 0) {
         if (err.message.length > 0) {
-          secondary = err.message
+          secondary = err.message;
         }
         }
-        setErrors([{
-          primary: 'Failed to load report data',
-          secondary: secondary,
-        }])
+        setErrors([
+          {
+            primary: "Failed to load report data",
+            secondary: secondary,
+          },
+        ]);
       }
       }
-      setAllocationData([])
+      setAllocationData([]);
     }
     }
 
 
-    setLoading(false)
-    setFetch(false)
+    setLoading(false);
+    setFetch(false);
   }
   }
   return (
   return (
     <Page active="reports.html">
     <Page active="reports.html">
@@ -211,71 +240,71 @@ const ReportsPage = () => {
         </div>
         </div>
       )}
       )}
 
 
-      {init && <Paper id="report">
-        <div className={classes.reportHeader}>
-          <div className={classes.titles}>
-            <Typography variant="h5">{title}</Typography>
-            <Subtitle
-              report={{ window, aggregateBy, accumulate }}
+      {init && (
+        <Paper id="report">
+          <div className={classes.reportHeader}>
+            <div className={classes.titles}>
+              <Typography variant="h5">{title}</Typography>
+              <Subtitle report={{ window, aggregateBy, accumulate }} />
+            </div>
+
+            <Controls
+              windowOptions={windowOptions}
+              window={window}
+              setWindow={(win) => {
+                searchParams.set("window", win);
+                routerHistory.push({
+                  search: `?${searchParams.toString()}`,
+                });
+              }}
+              aggregationOptions={aggregationOptions}
+              aggregateBy={aggregateBy}
+              setAggregateBy={(agg) => {
+                searchParams.set("agg", agg);
+                routerHistory.push({
+                  search: `?${searchParams.toString()}`,
+                });
+              }}
+              accumulateOptions={accumulateOptions}
+              accumulate={accumulate}
+              setAccumulate={(acc) => {
+                searchParams.set("acc", acc);
+                routerHistory.push({
+                  search: `?${searchParams.toString()}`,
+                });
+              }}
+              title={title}
+              cumulativeData={cumulativeData}
+              currency={currency}
+              currencyOptions={currencyCodes}
+              setCurrency={(curr) => {
+                searchParams.set("currency", curr);
+                routerHistory.push({
+                  search: `?${searchParams.toString()}`,
+                });
+              }}
             />
             />
           </div>
           </div>
 
 
-          <Controls
-            windowOptions={windowOptions}
-            window={window}
-            setWindow={(win) => {
-              searchParams.set('window', win);
-              routerHistory.push({
-                search: `?${searchParams.toString()}`,
-              });
-            }}
-            aggregationOptions={aggregationOptions}
-            aggregateBy={aggregateBy}
-            setAggregateBy={(agg) => {
-              searchParams.set('agg', agg);
-              routerHistory.push({
-                search: `?${searchParams.toString()}`,
-              });
-            }}
-            accumulateOptions={accumulateOptions}
-            accumulate={accumulate}
-            setAccumulate={(acc) => {
-              searchParams.set('acc', acc);
-              routerHistory.push({
-                search: `?${searchParams.toString()}`
-              });
-            }}
-            title={title}
-            cumulativeData={cumulativeData}
-            currency={currency}
-            currencyOptions={currencyCodes}
-            setCurrency={(curr) => {
-              searchParams.set('currency', curr);
-              routerHistory.push({
-                search: `?${searchParams.toString()}`
-              });
-            }}
-          />
-        </div>
-
-        {loading && (
-          <div style={{ display: 'flex', justifyContent: 'center' }}>
-            <div style={{ paddingTop: 100, paddingBottom: 100 }}>
-              <CircularProgress />
+          {loading && (
+            <div style={{ display: "flex", justifyContent: "center" }}>
+              <div style={{ paddingTop: 100, paddingBottom: 100 }}>
+                <CircularProgress />
+              </div>
             </div>
             </div>
-          </div>
-        )}
-        {!loading && (
-          <AllocationReport
-            allocationData={allocationData}
-            cumulativeData={cumulativeData}
-            totalData={totalData}
-            currency={currency}
-          />
-        )}
-      </Paper>}
+          )}
+          {!loading && (
+            <AllocationReport
+              allocationData={allocationData}
+              cumulativeData={cumulativeData}
+              totalData={totalData}
+              currency={currency}
+            />
+          )}
+        </Paper>
+      )}
     </Page>
     </Page>
-  )
-}
+  );
+};
 
 
 export default React.memo(ReportsPage);
 export default React.memo(ReportsPage);