diff --git a/changelog.md b/changelog.md
index a203828..08eaa17 100644
--- a/changelog.md
+++ b/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
diff --git a/client/src/pages/config/users/configman.jsx b/client/src/pages/config/users/configman.jsx
index d0158de..670207a 100644
--- a/client/src/pages/config/users/configman.jsx
+++ b/client/src/pages/config/users/configman.jsx
@@ -687,6 +687,15 @@ const ConfigManagement = () => {
+
+
+
+
+
diff --git a/client/src/pages/dashboard/components/plot.jsx b/client/src/pages/dashboard/components/plot.jsx
index d602dfe..1b208d1 100644
--- a/client/src/pages/dashboard/components/plot.jsx
+++ b/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
}
};
-
- 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));
- }
-
- const { primary, secondary } = theme.palette.text;
- const line = theme.palette.divider;
-
const [options, setOptions] = useState(areaChartOptions);
useEffect(() => {
+ let xAxis = [];
+
+ 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 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;
+ }
+ }
+ })
+ });
+ });
+
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,
+ tickAmount: xAxis.length,
},
- yaxis: [{
+ 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[0].Label,
+ text: thisdata.Label,
}
- },
- {
- opposite: true,
- labels: {
- style: {
- colors: [secondary]
- }
- },
- title: {
- text: data[1].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
- Server Resources
+ {title}
+
-
- ;
+
+
diff --git a/client/src/pages/dashboard/index.jsx b/client/src/pages/dashboard/index.jsx
index dd98ab0..f4226d7 100644
--- a/client/src/pages/dashboard/index.jsx
+++ b/client/src/pages/dashboard/index.jsx
@@ -175,7 +175,29 @@ const DashboardDefault = () => {
{/* row 2 */}
-
+
+
+
+
+
+ Income Overview
+
+
+
+
+
+
+
+ This Week Statistics
+
+ $7,650
+
+
+
+
+
+
+
@@ -209,6 +231,7 @@ const DashboardDefault = () => {
+
diff --git a/package.json b/package.json
index 75a6acf..8ad6394 100644
--- a/package.json
+++ b/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",
diff --git a/src/metrics/aggl.go b/src/metrics/aggl.go
index 1ccc97f..66d9873 100644
--- a/src/metrics/aggl.go
+++ b/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()
diff --git a/src/metrics/api.go b/src/metrics/api.go
index 5e4c5c5..7a3f6fc 100644
--- a/src/metrics/api.go
+++ b/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)
diff --git a/src/metrics/system.go b/src/metrics/system.go
index 89dbb05..d5d3592 100644
--- a/src/metrics/system.go
+++ b/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") != "" {