Selaa lähdekoodia

[release] v0.12.0-unstable5

Yann Stepienik 1 vuosi sitten
vanhempi
commit
33590ce369

+ 5 - 0
changelog.md

@@ -1,3 +1,8 @@
+## Version 0.12.0
+ - New Dashboard
+ - New metrics gathering system
+ - Added Button to force reset HTTPS cert in settings
+
 ## Version 0.11.3
  - Fix missing even subscriber on export
 

+ 9 - 0
client/src/pages/config/users/configman.jsx

@@ -687,6 +687,15 @@ const ConfigManagement = () => {
                     </Stack>
                   </Grid>
 
+                  <Grid item xs={12}>
+                    <CosmosCheckbox
+                      label={"Force HTTPS Certificate Renewal On Next Save"}
+                      name="ForceHTTPSCertificateRenewal"
+                      formik={formik}
+                    />
+                  </Grid>
+
+                    
                 </Grid>
               </MainCard>
 

+ 83 - 80
client/src/pages/dashboard/components/plot.jsx

@@ -45,9 +45,12 @@ function toUTC(date, time) {
   return formatDate(now, time);
 }
 
-const PlotComponent = ({ data, defaultSlot = 'day' }) => {
+const PlotComponent = ({ title, data, defaultSlot = 'latest' }) => {
   const [slot, setSlot] = useState(defaultSlot);
   const theme = useTheme();
+  const { primary, secondary } = theme.palette.text;
+  const line = theme.palette.divider;
+  const [series, setSeries] = useState([]);
 
   // chart options
   const areaChartOptions = {
@@ -69,116 +72,108 @@ const PlotComponent = ({ data, defaultSlot = 'day' }) => {
       strokeDashArray: 0
     }
   };
+  const [options, setOptions] = useState(areaChartOptions);
 
-  let hourlyDates = [];
-  for(let i = 0; i < 48; i++) {
-    let now = new Date();
-    now.setHours(now.getHours() - i);
-    now.setMinutes(0);
-    now.setSeconds(0);
-    // get as YYYY-MM-DD HH:MM:SS
-    hourlyDates.unshift(formatDate(now, true));
-  }
-
-  let dailyDates = [];
-  for(let i = 0; i < 30; i++) {
-    let now = new Date();
-    now.setDate(now.getDate() - i);
-    dailyDates.unshift(formatDate(now));
-  }
+  useEffect(() => {
+    let xAxis = [];
 
-  const { primary, secondary } = theme.palette.text;
-  const line = theme.palette.divider;
+    if(slot === 'latest') {
+      for(let i = 0; i < 100; i++) {
+        xAxis.unshift(i);
+      }
+    }
+    else if(slot === 'hourly') {
+      for(let i = 0; i < 48; i++) {
+        let now = new Date();
+        now.setHours(now.getHours() - i);
+        now.setMinutes(0);
+        now.setSeconds(0);
+        xAxis.unshift(formatDate(now, true));
+      }
+    } else if(slot === 'daily') {
+      for(let i = 0; i < 30; i++) {
+        let now = new Date();
+        now.setDate(now.getDate() - i);
+        xAxis.unshift(formatDate(now));
+      }
+    }
 
-  const [options, setOptions] = useState(areaChartOptions);
+    const dataSeries = [];
+    data.forEach((serie) => {
+      dataSeries.push({
+        name: serie.Label,
+        dataAxis: xAxis.map((date) => {
+          if(slot === 'latest') {
+            return serie.Values[serie.Values.length - 1 - date] ? 
+              serie.Values[serie.Values.length - 1 - date].Value :
+              0;
+          } else {
+            let key = slot === 'hourly' ? "hour_" : "day_";
+            let k = key + toUTC(date, slot === 'hourly');
+            if (k in serie.ValuesAggl) {
+              return serie.ValuesAggl[k].Value;
+            } else {
+              return 0;
+            }
+          }
+        })
+      });
+    });
 
-  useEffect(() => {
     setOptions((prevState) => ({
       ...prevState,
       colors: [theme.palette.primary.main, theme.palette.secondary.main],
       xaxis: {
-        categories:
-          slot === 'hourly'
-            ? hourlyDates.map((date) => date.split(' ')[1])
-            : dailyDates,
+        categories: 
+        slot === 'hourly'
+          ? xAxis.map((date) => date.split(' ')[1])
+          : xAxis,
         labels: {
           style: {
-            fontSize: '11px',
+            fontSize: slot === 'latest' ? '0' : '11px',
           }
         },
         axisBorder: {
           show: true,
           color: line
         },
-        tickAmount: slot === 'hourly' ? hourlyDates.length : dailyDates.length,
-      },
-      yaxis: [{
-        labels: {
-          style: {
-            colors: [secondary]
-          }
-        },
-        title: {
-          text: data[0].Label,
-        }
+        tickAmount: xAxis.length,
       },
-      {
-        opposite: true,
+      yaxis: data.map((thisdata, ida) => ({
+        opposite: ida === 1, 
         labels: {
           style: {
             colors: [secondary]
+          },
+          
+          formatter: (num) => {
+            if (Math.abs(num) >= 1e9) {
+              return (num / 1e9).toFixed(1) + 'G'; // Convert to Millions
+            } else if (Math.abs(num) >= 1e6) {
+                return (num / 1e6).toFixed(1) + 'M'; // Convert to Millions
+            } else if (Math.abs(num) >= 1e3) {
+                return (num / 1e3).toFixed(1) + 'K'; // Convert to Thousands
+            } else {
+                return num.toString();
+            }
           }
         },
         title: {
-          text: data[1].Label,
+          text: thisdata.Label,
         }
-      }
-      ],
+      })),
       grid: {
         borderColor: line
       },
       tooltip: {
-        theme: 'light'
+        theme: theme.palette.mode,
       }
     }));
-  }, [primary, secondary, line, theme, slot]);
-
-  let dataSeries = [];
-  data.forEach((serie) => {
-    dataSeries.push({
-      name: serie.Label,
-      dataDaily: dailyDates.map((date) => {
-        let k = "day_" + toUTC(date);
-        if (k in serie.ValuesAggl) {
-          return serie.ValuesAggl[k].Value;
-        } else {
-          console.log(k)
-          return 0;
-        }
-      }),
-      dataHourly: hourlyDates.map((date) => {
-        let k = "hour_" + toUTC(date, true);
-        if (k in serie.ValuesAggl) {
-          return serie.ValuesAggl[k].Value;
-        } else {
-          return 0;
-        }
-      }),
-    });
-  });
-
-  const [series, setSeries] = useState(dataSeries.map((serie) => {
-    return {
-      name: serie.name,
-      data: slot === 'hourly' ? serie.dataHourly : serie.dataDaily
-    }
-  }));
 
-  useEffect(() => {
     setSeries(dataSeries.map((serie) => {
       return {
         name: serie.name,
-        data: slot === 'hourly' ? serie.dataHourly : serie.dataDaily
+        data: serie.dataAxis
       }
     }));
   }, [slot, data]);
@@ -187,10 +182,18 @@ const PlotComponent = ({ data, defaultSlot = 'day' }) => {
   return <Grid item xs={12} md={7} lg={8}>
     <Grid container alignItems="center" justifyContent="space-between">
       <Grid item>
-        <Typography variant="h5">Server Resources</Typography>
+        <Typography variant="h5">{title}</Typography>
       </Grid>
       <Grid item>
         <Stack direction="row" alignItems="center" spacing={0}>
+          <Button
+            size="small"
+            onClick={() => setSlot('latest')}
+            color={slot === 'latest' ? 'primary' : 'secondary'}
+            variant={slot === 'latest' ? 'outlined' : 'text'}
+          >
+            Latest
+          </Button>
           <Button
             size="small"
             onClick={() => setSlot('hourly')}
@@ -211,8 +214,8 @@ const PlotComponent = ({ data, defaultSlot = 'day' }) => {
       </Grid>
     </Grid>
     <MainCard content={false} sx={{ mt: 1.5 }}>
-      <Box sx={{ pt: 1, pr: 2 }} className="force-light">
-        <ReactApexChart options={options} series={series} type="area" height={450} />;
+      <Box sx={{ pt: 1, pr: 2 }}>
+        <ReactApexChart options={options} series={series} type="area" height={450} />
       </Box>
     </MainCard>
   </Grid>

+ 24 - 1
client/src/pages/dashboard/index.jsx

@@ -175,7 +175,29 @@ const DashboardDefault = () => {
 
                 {/* row 2 */}
                 
-                <PlotComponent data={[metrics["cosmos.system.cpu.0"], metrics["cosmos.system.ram"]]}/>
+                <PlotComponent title={'Resources'} data={[metrics["cosmos.system.cpu.0"], metrics["cosmos.system.ram"]]}/>
+               
+                <Grid item xs={12} md={5} lg={4}>
+                    <Grid container alignItems="center" justifyContent="space-between">
+                        <Grid item>
+                            <Typography variant="h5">Income Overview</Typography>
+                        </Grid>
+                        <Grid item />
+                    </Grid>
+                    <MainCard sx={{ mt: 2 }} content={false}>
+                        <Box sx={{ p: 3, pb: 0 }}>
+                            <Stack spacing={2}>
+                                <Typography variant="h6" color="textSecondary">
+                                    This Week Statistics
+                                </Typography>
+                                <Typography variant="h3">$7,650</Typography>
+                            </Stack>
+                        </Box>
+                        <MonthlyBarChart />
+                    </MainCard>
+                </Grid>
+               
+                <PlotComponent title={'Network'} data={[metrics["cosmos.system.netTx"], metrics["cosmos.system.netRx"]]}/>
                 
                 <Grid item xs={12} md={5} lg={4}>
                     <Grid container alignItems="center" justifyContent="space-between">
@@ -209,6 +231,7 @@ const DashboardDefault = () => {
                         <OrdersTable />
                     </MainCard>
                 </Grid>
+
                 <Grid item xs={12} md={5} lg={4}>
                     <Grid container alignItems="center" justifyContent="space-between">
                         <Grid item>

+ 2 - 2
package.json

@@ -1,6 +1,6 @@
 {
   "name": "cosmos-server",
-  "version": "0.12.0-unstable4",
+  "version": "0.12.0-unstable5",
   "description": "",
   "main": "test-server.js",
   "bugs": {
@@ -67,7 +67,7 @@
     "start": "env COSMOS_CONFIG_FOLDER=/mnt/e/work/Cosmos-Server/zz_test_config/ CONFIG_FILE=./config_dev.json EZ=UTC ACME_STAGING=true build/cosmos",
     "build": "sh build.sh",
     "dev": "npm run build && npm run start",
-    "dockerdevbuild": "sh build.sh && docker build -f dockerfile.local --tag cosmos-dev .",
+    "dockerdevbuild": "docker build -f dockerfile.local --tag cosmos-dev .",
     "dockerdevrun": "docker stop cosmos-dev; docker rm cosmos-dev; docker run --cap-add NET_ADMIN -d -p 7200:443 -p 80:80 -p 53:53 -p 443:443 -p 4242:4242 -e DOCKER_HOST=tcp://host.docker.internal:2375 -e COSMOS_MONGODB=$MONGODB -e COSMOS_LOG_LEVEL=DEBUG -v /:/mnt/host  --restart=unless-stopped -h cosmos-dev --name cosmos-dev cosmos-dev",
     "dockerdev": "npm run client-build && npm run dockerdevbuild && npm run dockerdevrun",
     "demo": "vite build --base=/cosmos-ui/ --mode demo",

+ 21 - 5
src/metrics/aggl.go

@@ -31,7 +31,7 @@ type DataDefDB struct {
 	AggloType string
 }
 
-func AggloMetrics() {
+func AggloMetrics() []DataDefDB {
 	lock <- true
 	defer func() { <-lock }()
 
@@ -42,7 +42,7 @@ func AggloMetrics() {
 	c, errCo := utils.GetCollection(utils.GetRootAppId(), "metrics")
 	if errCo != nil {
 			utils.Error("Metrics - Database Connect", errCo)
-			return
+			return []DataDefDB{}
 	}
 
 	// get all metrics from database
@@ -50,13 +50,13 @@ func AggloMetrics() {
 	cursor, err := c.Find(nil, map[string]interface{}{})
 	if err != nil {
 		utils.Error("Metrics: Error fetching metrics", err)
-		return
+		return []DataDefDB{}
 	}
 	defer cursor.Close(nil)
 	
 	if err = cursor.All(nil, &metrics); err != nil {
 		utils.Error("Metrics: Error decoding metrics", err)
-		return
+		return []DataDefDB{}
 	}
 
 	// populate aggregation pools
@@ -153,8 +153,18 @@ func AggloMetrics() {
 		metrics[metInd] = metric
 	}
 
+	return metrics
+}
+
+func CommitAggl(metrics []DataDefDB) {
 	utils.Log("Metrics: Agglomeration done. Saving to DB")
 
+	c, errCo := utils.GetCollection(utils.GetRootAppId(), "metrics")
+	if errCo != nil {
+			utils.Error("Metrics - Database Connect", errCo)
+			return
+	}
+
 	// save metrics
 	for _, metric := range metrics {
 		options := options.Update().SetUpsert(true)
@@ -166,12 +176,18 @@ func AggloMetrics() {
 			return
 		}
 	}
+
+	utils.Log("Metrics: Agglomeration saved to DB")
+}
+
+func AggloAndCommitMetrics() {
+	CommitAggl(AggloMetrics())
 }
 
 func InitAggl() {
 	go func() {
 		s := gocron.NewScheduler()
-		s.Every(1).Hour().From(gocron.NextTick()).Do(AggloMetrics)
+		s.Every(1).Hour().From(gocron.NextTick()).Do(AggloAndCommitMetrics)
 		// s.Every(3).Minute().From(gocron.NextTick()).Do(AggloMetrics)
 
 		s.Start()

+ 1 - 21
src/metrics/api.go

@@ -13,29 +13,9 @@ func API_GetMetrics(w http.ResponseWriter, req *http.Request) {
 	}
 
 	if(req.Method == "GET") {
-		c, errCo := utils.GetCollection(utils.GetRootAppId(), "metrics")
-		if errCo != nil {
-				utils.Error("Metrics - Database Connect", errCo)
-				return
-		}
-
-		// get all metrics from database
-		var metrics []DataDefDB
-		cursor, err := c.Find(nil, map[string]interface{}{})
-		if err != nil {
-			utils.Error("Metrics: Error fetching metrics", err)
-			return
-		}
-		defer cursor.Close(nil)
-		
-		if err = cursor.All(nil, &metrics); err != nil {
-			utils.Error("Metrics: Error decoding metrics", err)
-			return
-		}
-		
 		json.NewEncoder(w).Encode(map[string]interface{}{
 			"status": "OK",
-			"data": metrics,
+			"data": AggloMetrics(),
 		})
 	} else {
 		utils.Error("SettingGet: Method not allowed" + req.Method, nil)

+ 1 - 1
src/metrics/system.go

@@ -124,7 +124,7 @@ func GetSystemMetrics() {
 	}
 
   for _, part := range parts {
-		if strings.HasPrefix(part.Mountpoint, "/dev") || strings.HasPrefix(part.Mountpoint, "/mnt") {
+		if strings.HasPrefix(part.Mountpoint, "/dev") || (strings.HasPrefix(part.Mountpoint, "/mnt") && !strings.HasPrefix(part.Mountpoint, "/mnt/host")) {
 			realMount := part.Mountpoint
 			
 			if os.Getenv("HOSTANME") != "" {