feat: Add stats bar component to display miner performance metrics and update dashboard layout
This commit is contained in:
parent
aefe328254
commit
7d6e6e9c42
10 changed files with 824 additions and 90 deletions
245
docs/docs.go
245
docs/docs.go
|
|
@ -615,6 +615,9 @@ const docTemplate = `{
|
|||
"configPath": {
|
||||
"type": "string"
|
||||
},
|
||||
"full_stats": {
|
||||
"$ref": "#/definitions/mining.XMRigSummary"
|
||||
},
|
||||
"hashrateHistory": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
|
|
@ -646,6 +649,248 @@ const docTemplate = `{
|
|||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"mining.XMRigSummary": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"algo": {
|
||||
"type": "string"
|
||||
},
|
||||
"algorithms": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"connection": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"accepted": {
|
||||
"type": "integer"
|
||||
},
|
||||
"algo": {
|
||||
"type": "string"
|
||||
},
|
||||
"avg_time": {
|
||||
"type": "integer"
|
||||
},
|
||||
"avg_time_ms": {
|
||||
"type": "integer"
|
||||
},
|
||||
"diff": {
|
||||
"type": "integer"
|
||||
},
|
||||
"failures": {
|
||||
"type": "integer"
|
||||
},
|
||||
"hashes_total": {
|
||||
"type": "integer"
|
||||
},
|
||||
"ip": {
|
||||
"type": "string"
|
||||
},
|
||||
"ping": {
|
||||
"type": "integer"
|
||||
},
|
||||
"pool": {
|
||||
"type": "string"
|
||||
},
|
||||
"rejected": {
|
||||
"type": "integer"
|
||||
},
|
||||
"tls": {
|
||||
"type": "string"
|
||||
},
|
||||
"tls-fingerprint": {
|
||||
"type": "string"
|
||||
},
|
||||
"uptime": {
|
||||
"type": "integer"
|
||||
},
|
||||
"uptime_ms": {
|
||||
"type": "integer"
|
||||
}
|
||||
}
|
||||
},
|
||||
"cpu": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"64_bit": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"aes": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"arch": {
|
||||
"type": "string"
|
||||
},
|
||||
"assembly": {
|
||||
"type": "string"
|
||||
},
|
||||
"avx2": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"backend": {
|
||||
"type": "string"
|
||||
},
|
||||
"brand": {
|
||||
"type": "string"
|
||||
},
|
||||
"cores": {
|
||||
"type": "integer"
|
||||
},
|
||||
"family": {
|
||||
"type": "integer"
|
||||
},
|
||||
"flags": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"l2": {
|
||||
"type": "integer"
|
||||
},
|
||||
"l3": {
|
||||
"type": "integer"
|
||||
},
|
||||
"model": {
|
||||
"type": "integer"
|
||||
},
|
||||
"msr": {
|
||||
"type": "string"
|
||||
},
|
||||
"nodes": {
|
||||
"type": "integer"
|
||||
},
|
||||
"packages": {
|
||||
"type": "integer"
|
||||
},
|
||||
"proc_info": {
|
||||
"type": "integer"
|
||||
},
|
||||
"stepping": {
|
||||
"type": "integer"
|
||||
},
|
||||
"threads": {
|
||||
"type": "integer"
|
||||
},
|
||||
"x64": {
|
||||
"type": "boolean"
|
||||
}
|
||||
}
|
||||
},
|
||||
"donate_level": {
|
||||
"type": "integer"
|
||||
},
|
||||
"features": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"hashrate": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"highest": {
|
||||
"type": "number"
|
||||
},
|
||||
"total": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "number"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"hugepages": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "integer"
|
||||
}
|
||||
},
|
||||
"id": {
|
||||
"type": "string"
|
||||
},
|
||||
"kind": {
|
||||
"type": "string"
|
||||
},
|
||||
"paused": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"resources": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"hardware_concurrency": {
|
||||
"type": "integer"
|
||||
},
|
||||
"load_average": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "number"
|
||||
}
|
||||
},
|
||||
"memory": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"free": {
|
||||
"type": "integer"
|
||||
},
|
||||
"resident_set_memory": {
|
||||
"type": "integer"
|
||||
},
|
||||
"total": {
|
||||
"type": "integer"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"restricted": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"results": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"avg_time": {
|
||||
"type": "integer"
|
||||
},
|
||||
"avg_time_ms": {
|
||||
"type": "integer"
|
||||
},
|
||||
"best": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "integer"
|
||||
}
|
||||
},
|
||||
"diff_current": {
|
||||
"type": "integer"
|
||||
},
|
||||
"hashes_total": {
|
||||
"type": "integer"
|
||||
},
|
||||
"shares_good": {
|
||||
"type": "integer"
|
||||
},
|
||||
"shares_total": {
|
||||
"type": "integer"
|
||||
}
|
||||
}
|
||||
},
|
||||
"ua": {
|
||||
"type": "string"
|
||||
},
|
||||
"uptime": {
|
||||
"type": "integer"
|
||||
},
|
||||
"version": {
|
||||
"type": "string"
|
||||
},
|
||||
"worker_id": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}`
|
||||
|
|
|
|||
|
|
@ -609,6 +609,9 @@
|
|||
"configPath": {
|
||||
"type": "string"
|
||||
},
|
||||
"full_stats": {
|
||||
"$ref": "#/definitions/mining.XMRigSummary"
|
||||
},
|
||||
"hashrateHistory": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
|
|
@ -640,6 +643,248 @@
|
|||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"mining.XMRigSummary": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"algo": {
|
||||
"type": "string"
|
||||
},
|
||||
"algorithms": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"connection": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"accepted": {
|
||||
"type": "integer"
|
||||
},
|
||||
"algo": {
|
||||
"type": "string"
|
||||
},
|
||||
"avg_time": {
|
||||
"type": "integer"
|
||||
},
|
||||
"avg_time_ms": {
|
||||
"type": "integer"
|
||||
},
|
||||
"diff": {
|
||||
"type": "integer"
|
||||
},
|
||||
"failures": {
|
||||
"type": "integer"
|
||||
},
|
||||
"hashes_total": {
|
||||
"type": "integer"
|
||||
},
|
||||
"ip": {
|
||||
"type": "string"
|
||||
},
|
||||
"ping": {
|
||||
"type": "integer"
|
||||
},
|
||||
"pool": {
|
||||
"type": "string"
|
||||
},
|
||||
"rejected": {
|
||||
"type": "integer"
|
||||
},
|
||||
"tls": {
|
||||
"type": "string"
|
||||
},
|
||||
"tls-fingerprint": {
|
||||
"type": "string"
|
||||
},
|
||||
"uptime": {
|
||||
"type": "integer"
|
||||
},
|
||||
"uptime_ms": {
|
||||
"type": "integer"
|
||||
}
|
||||
}
|
||||
},
|
||||
"cpu": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"64_bit": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"aes": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"arch": {
|
||||
"type": "string"
|
||||
},
|
||||
"assembly": {
|
||||
"type": "string"
|
||||
},
|
||||
"avx2": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"backend": {
|
||||
"type": "string"
|
||||
},
|
||||
"brand": {
|
||||
"type": "string"
|
||||
},
|
||||
"cores": {
|
||||
"type": "integer"
|
||||
},
|
||||
"family": {
|
||||
"type": "integer"
|
||||
},
|
||||
"flags": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"l2": {
|
||||
"type": "integer"
|
||||
},
|
||||
"l3": {
|
||||
"type": "integer"
|
||||
},
|
||||
"model": {
|
||||
"type": "integer"
|
||||
},
|
||||
"msr": {
|
||||
"type": "string"
|
||||
},
|
||||
"nodes": {
|
||||
"type": "integer"
|
||||
},
|
||||
"packages": {
|
||||
"type": "integer"
|
||||
},
|
||||
"proc_info": {
|
||||
"type": "integer"
|
||||
},
|
||||
"stepping": {
|
||||
"type": "integer"
|
||||
},
|
||||
"threads": {
|
||||
"type": "integer"
|
||||
},
|
||||
"x64": {
|
||||
"type": "boolean"
|
||||
}
|
||||
}
|
||||
},
|
||||
"donate_level": {
|
||||
"type": "integer"
|
||||
},
|
||||
"features": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"hashrate": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"highest": {
|
||||
"type": "number"
|
||||
},
|
||||
"total": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "number"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"hugepages": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "integer"
|
||||
}
|
||||
},
|
||||
"id": {
|
||||
"type": "string"
|
||||
},
|
||||
"kind": {
|
||||
"type": "string"
|
||||
},
|
||||
"paused": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"resources": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"hardware_concurrency": {
|
||||
"type": "integer"
|
||||
},
|
||||
"load_average": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "number"
|
||||
}
|
||||
},
|
||||
"memory": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"free": {
|
||||
"type": "integer"
|
||||
},
|
||||
"resident_set_memory": {
|
||||
"type": "integer"
|
||||
},
|
||||
"total": {
|
||||
"type": "integer"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"restricted": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"results": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"avg_time": {
|
||||
"type": "integer"
|
||||
},
|
||||
"avg_time_ms": {
|
||||
"type": "integer"
|
||||
},
|
||||
"best": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "integer"
|
||||
}
|
||||
},
|
||||
"diff_current": {
|
||||
"type": "integer"
|
||||
},
|
||||
"hashes_total": {
|
||||
"type": "integer"
|
||||
},
|
||||
"shares_good": {
|
||||
"type": "integer"
|
||||
},
|
||||
"shares_total": {
|
||||
"type": "integer"
|
||||
}
|
||||
}
|
||||
},
|
||||
"ua": {
|
||||
"type": "string"
|
||||
},
|
||||
"uptime": {
|
||||
"type": "integer"
|
||||
},
|
||||
"version": {
|
||||
"type": "string"
|
||||
},
|
||||
"worker_id": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -93,6 +93,8 @@ definitions:
|
|||
$ref: '#/definitions/mining.API'
|
||||
configPath:
|
||||
type: string
|
||||
full_stats:
|
||||
$ref: '#/definitions/mining.XMRigSummary'
|
||||
hashrateHistory:
|
||||
items:
|
||||
$ref: '#/definitions/mining.HashratePoint'
|
||||
|
|
@ -114,6 +116,165 @@ definitions:
|
|||
version:
|
||||
type: string
|
||||
type: object
|
||||
mining.XMRigSummary:
|
||||
properties:
|
||||
algo:
|
||||
type: string
|
||||
algorithms:
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
connection:
|
||||
properties:
|
||||
accepted:
|
||||
type: integer
|
||||
algo:
|
||||
type: string
|
||||
avg_time:
|
||||
type: integer
|
||||
avg_time_ms:
|
||||
type: integer
|
||||
diff:
|
||||
type: integer
|
||||
failures:
|
||||
type: integer
|
||||
hashes_total:
|
||||
type: integer
|
||||
ip:
|
||||
type: string
|
||||
ping:
|
||||
type: integer
|
||||
pool:
|
||||
type: string
|
||||
rejected:
|
||||
type: integer
|
||||
tls:
|
||||
type: string
|
||||
tls-fingerprint:
|
||||
type: string
|
||||
uptime:
|
||||
type: integer
|
||||
uptime_ms:
|
||||
type: integer
|
||||
type: object
|
||||
cpu:
|
||||
properties:
|
||||
64_bit:
|
||||
type: boolean
|
||||
aes:
|
||||
type: boolean
|
||||
arch:
|
||||
type: string
|
||||
assembly:
|
||||
type: string
|
||||
avx2:
|
||||
type: boolean
|
||||
backend:
|
||||
type: string
|
||||
brand:
|
||||
type: string
|
||||
cores:
|
||||
type: integer
|
||||
family:
|
||||
type: integer
|
||||
flags:
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
l2:
|
||||
type: integer
|
||||
l3:
|
||||
type: integer
|
||||
model:
|
||||
type: integer
|
||||
msr:
|
||||
type: string
|
||||
nodes:
|
||||
type: integer
|
||||
packages:
|
||||
type: integer
|
||||
proc_info:
|
||||
type: integer
|
||||
stepping:
|
||||
type: integer
|
||||
threads:
|
||||
type: integer
|
||||
x64:
|
||||
type: boolean
|
||||
type: object
|
||||
donate_level:
|
||||
type: integer
|
||||
features:
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
hashrate:
|
||||
properties:
|
||||
highest:
|
||||
type: number
|
||||
total:
|
||||
items:
|
||||
type: number
|
||||
type: array
|
||||
type: object
|
||||
hugepages:
|
||||
items:
|
||||
type: integer
|
||||
type: array
|
||||
id:
|
||||
type: string
|
||||
kind:
|
||||
type: string
|
||||
paused:
|
||||
type: boolean
|
||||
resources:
|
||||
properties:
|
||||
hardware_concurrency:
|
||||
type: integer
|
||||
load_average:
|
||||
items:
|
||||
type: number
|
||||
type: array
|
||||
memory:
|
||||
properties:
|
||||
free:
|
||||
type: integer
|
||||
resident_set_memory:
|
||||
type: integer
|
||||
total:
|
||||
type: integer
|
||||
type: object
|
||||
type: object
|
||||
restricted:
|
||||
type: boolean
|
||||
results:
|
||||
properties:
|
||||
avg_time:
|
||||
type: integer
|
||||
avg_time_ms:
|
||||
type: integer
|
||||
best:
|
||||
items:
|
||||
type: integer
|
||||
type: array
|
||||
diff_current:
|
||||
type: integer
|
||||
hashes_total:
|
||||
type: integer
|
||||
shares_good:
|
||||
type: integer
|
||||
shares_total:
|
||||
type: integer
|
||||
type: object
|
||||
ua:
|
||||
type: string
|
||||
uptime:
|
||||
type: integer
|
||||
version:
|
||||
type: string
|
||||
worker_id:
|
||||
type: string
|
||||
type: object
|
||||
host: localhost:8080
|
||||
info:
|
||||
contact: {}
|
||||
|
|
|
|||
|
|
@ -139,17 +139,82 @@ type API struct {
|
|||
ListenPort int `json:"listenPort"`
|
||||
}
|
||||
|
||||
// XMRigSummary represents the summary of an XMRig miner's performance.
|
||||
// XMRigSummary represents the full JSON response from the XMRig API.
|
||||
type XMRigSummary struct {
|
||||
Hashrate struct {
|
||||
Total []float64 `json:"total"`
|
||||
} `json:"hashrate"`
|
||||
Results struct {
|
||||
SharesGood uint64 `json:"shares_good"`
|
||||
SharesTotal uint64 `json:"shares_total"`
|
||||
ID string `json:"id"`
|
||||
WorkerID string `json:"worker_id"`
|
||||
Uptime int `json:"uptime"`
|
||||
Restricted bool `json:"restricted"`
|
||||
Resources struct {
|
||||
Memory struct {
|
||||
Free int64 `json:"free"`
|
||||
Total int64 `json:"total"`
|
||||
ResidentSetMemory int64 `json:"resident_set_memory"`
|
||||
} `json:"memory"`
|
||||
LoadAverage []float64 `json:"load_average"`
|
||||
HardwareConcurrency int `json:"hardware_concurrency"`
|
||||
} `json:"resources"`
|
||||
Features []string `json:"features"`
|
||||
Results struct {
|
||||
DiffCurrent int `json:"diff_current"`
|
||||
SharesGood int `json:"shares_good"`
|
||||
SharesTotal int `json:"shares_total"`
|
||||
AvgTime int `json:"avg_time"`
|
||||
AvgTimeMS int `json:"avg_time_ms"`
|
||||
HashesTotal int `json:"hashes_total"`
|
||||
Best []int `json:"best"`
|
||||
} `json:"results"`
|
||||
Uptime uint64 `json:"uptime"`
|
||||
Algorithm string `json:"algorithm"`
|
||||
Algo string `json:"algo"`
|
||||
Connection struct {
|
||||
Pool string `json:"pool"`
|
||||
IP string `json:"ip"`
|
||||
Uptime int `json:"uptime"`
|
||||
UptimeMS int `json:"uptime_ms"`
|
||||
Ping int `json:"ping"`
|
||||
Failures int `json:"failures"`
|
||||
TLS string `json:"tls"`
|
||||
TLSFingerprint string `json:"tls-fingerprint"`
|
||||
Algo string `json:"algo"`
|
||||
Diff int `json:"diff"`
|
||||
Accepted int `json:"accepted"`
|
||||
Rejected int `json:"rejected"`
|
||||
AvgTime int `json:"avg_time"`
|
||||
AvgTimeMS int `json:"avg_time_ms"`
|
||||
HashesTotal int `json:"hashes_total"`
|
||||
} `json:"connection"`
|
||||
Version string `json:"version"`
|
||||
Kind string `json:"kind"`
|
||||
UA string `json:"ua"`
|
||||
CPU struct {
|
||||
Brand string `json:"brand"`
|
||||
Family int `json:"family"`
|
||||
Model int `json:"model"`
|
||||
Stepping int `json:"stepping"`
|
||||
ProcInfo int `json:"proc_info"`
|
||||
AES bool `json:"aes"`
|
||||
AVX2 bool `json:"avx2"`
|
||||
X64 bool `json:"x64"`
|
||||
Is64Bit bool `json:"64_bit"`
|
||||
L2 int `json:"l2"`
|
||||
L3 int `json:"l3"`
|
||||
Cores int `json:"cores"`
|
||||
Threads int `json:"threads"`
|
||||
Packages int `json:"packages"`
|
||||
Nodes int `json:"nodes"`
|
||||
Backend string `json:"backend"`
|
||||
MSR string `json:"msr"`
|
||||
Assembly string `json:"assembly"`
|
||||
Arch string `json:"arch"`
|
||||
Flags []string `json:"flags"`
|
||||
} `json:"cpu"`
|
||||
DonateLevel int `json:"donate_level"`
|
||||
Paused bool `json:"paused"`
|
||||
Algorithms []string `json:"algorithms"`
|
||||
Hashrate struct {
|
||||
Total []float64 `json:"total"`
|
||||
Highest float64 `json:"highest"`
|
||||
} `json:"hashrate"`
|
||||
Hugepages []int `json:"hugepages"`
|
||||
}
|
||||
|
||||
// AvailableMiner represents a miner that is available for use.
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ import (
|
|||
// XMRigMiner represents an XMRig miner, embedding the BaseMiner for common functionality.
|
||||
type XMRigMiner struct {
|
||||
BaseMiner
|
||||
FullStats *XMRigSummary `json:"full_stats,omitempty"`
|
||||
}
|
||||
|
||||
var httpClient = &http.Client{
|
||||
|
|
|
|||
|
|
@ -100,6 +100,7 @@ func addCliArgs(config *Config, args *[]string) {
|
|||
if config.TLS {
|
||||
*args = append(*args, "--tls")
|
||||
}
|
||||
*args = append(*args, "--donate-level", "1")
|
||||
}
|
||||
|
||||
// createConfig creates a JSON configuration file for the XMRig miner.
|
||||
|
|
|
|||
|
|
@ -34,6 +34,9 @@ func (m *XMRigMiner) GetStats() (*PerformanceMetrics, error) {
|
|||
return nil, err
|
||||
}
|
||||
|
||||
// Store the full summary in the miner struct
|
||||
m.FullStats = &summary
|
||||
|
||||
var hashrate int
|
||||
if len(summary.Hashrate.Total) > 0 {
|
||||
hashrate = int(summary.Hashrate.Total[0])
|
||||
|
|
@ -41,9 +44,9 @@ func (m *XMRigMiner) GetStats() (*PerformanceMetrics, error) {
|
|||
|
||||
return &PerformanceMetrics{
|
||||
Hashrate: hashrate,
|
||||
Shares: int(summary.Results.SharesGood),
|
||||
Rejected: int(summary.Results.SharesTotal - summary.Results.SharesGood),
|
||||
Uptime: int(summary.Uptime),
|
||||
Algorithm: summary.Algorithm,
|
||||
Shares: summary.Results.SharesGood,
|
||||
Rejected: summary.Results.SharesTotal - summary.Results.SharesGood,
|
||||
Uptime: summary.Uptime,
|
||||
Algorithm: summary.Algo,
|
||||
}, nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,12 +1,4 @@
|
|||
<div class="dashboard-view">
|
||||
<div class="header-title">
|
||||
<wa-icon name="cpu" style="font-size: 1.5rem;"></wa-icon>
|
||||
<span>Mining Control</span>
|
||||
<wa-button variant="neutral" appearance="plain" (click)="toggleProfileManager()">
|
||||
<wa-icon name="list-alt" label="Profile Manager"></wa-icon>
|
||||
</wa-button>
|
||||
</div>
|
||||
|
||||
@if (error()) {
|
||||
<wa-card class="card-error">
|
||||
<div slot="header">
|
||||
|
|
@ -17,75 +9,15 @@
|
|||
</wa-card>
|
||||
}
|
||||
|
||||
@if(showProfileManager()) {
|
||||
<div class="profile-manager-view">
|
||||
<snider-mining-profile-list></snider-mining-profile-list>
|
||||
<snider-mining-profile-create></snider-mining-profile-create>
|
||||
<!-- Consolidated Chart for All Running Miners -->
|
||||
@if (state().runningMiners.length > 0) {
|
||||
<div class="dashboard-charts">
|
||||
<snider-mining-stats-bar [stats]="state().runningMiners[0]?.full_stats"></snider-mining-stats-bar>
|
||||
<snider-mining-chart></snider-mining-chart>
|
||||
</div>
|
||||
} @else {
|
||||
<!-- Miner Summary and Controls -->
|
||||
@if (state().installedMiners.length > 0) {
|
||||
<div class="dashboard-summary">
|
||||
@for (miner of state().installedMiners; track miner.path) {
|
||||
<div class="miner-summary-item">
|
||||
<span class="miner-name">
|
||||
{{ miner.type }}
|
||||
<wa-tooltip>
|
||||
<div slot="content">Version: {{ miner.version }}</div>
|
||||
<wa-icon name="info-circle"></wa-icon>
|
||||
</wa-tooltip>
|
||||
</span>
|
||||
|
||||
@if (isMinerRunning(miner)) {
|
||||
<wa-button
|
||||
variant="danger"
|
||||
[disabled]="actionInProgress() === 'stop-' + miner.type"
|
||||
(click)="stopMiner(miner)">
|
||||
@if (actionInProgress() === 'stop-' + miner.type) {
|
||||
<wa-spinner class="button-spinner"></wa-spinner>
|
||||
} @else {
|
||||
<wa-icon name="stop-circle" slot="prefix"></wa-icon>
|
||||
Stop
|
||||
}
|
||||
</wa-button>
|
||||
} @else {
|
||||
@if(miner.type) {
|
||||
<div class="start-buttons">
|
||||
<wa-select
|
||||
[value]="selectedProfileIds().get(miner.type) ?? ''"
|
||||
(change)="handleProfileSelection(miner.type, $event)">
|
||||
<span slot="label">Profile</span>
|
||||
@for(profile of state().profiles; track profile.id) {
|
||||
@if(profile.minerType === miner.type) {
|
||||
<wa-option [value]="profile.id">{{ profile.name }}</wa-option>
|
||||
}
|
||||
}
|
||||
</wa-select>
|
||||
<wa-button
|
||||
variant="primary"
|
||||
[disabled]="!selectedProfileIds().get(miner.type) || actionInProgress()?.startsWith('start-')"
|
||||
(click)="startMiner(miner.type)">
|
||||
<wa-icon name="play-circle" slot="prefix"></wa-icon>
|
||||
Start
|
||||
</wa-button>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
|
||||
<!-- Consolidated Chart for All Running Miners -->
|
||||
@if (state().runningMiners.length > 0) {
|
||||
<div class="dashboard-charts">
|
||||
<snider-mining-chart></snider-mining-chart>
|
||||
</div>
|
||||
}
|
||||
|
||||
} @else {
|
||||
<div class="centered-container">
|
||||
<p>No miners installed. Open the Admin Panel to install one.</p>
|
||||
</div>
|
||||
}
|
||||
<div class="centered-container">
|
||||
<p>No miners running.</p>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import { MinerService } from './miner.service';
|
|||
import { ChartComponent } from './chart.component';
|
||||
import { ProfileListComponent } from './profile-list.component';
|
||||
import { ProfileCreateComponent } from './profile-create.component';
|
||||
import { StatsBarComponent } from './stats-bar.component';
|
||||
|
||||
// Import Web Awesome components
|
||||
import "@awesome.me/webawesome/dist/webawesome.js";
|
||||
|
|
@ -21,7 +22,7 @@ import '@awesome.me/webawesome/dist/components/select/select.js';
|
|||
selector: 'snider-mining-dashboard',
|
||||
standalone: true,
|
||||
schemas: [CUSTOM_ELEMENTS_SCHEMA],
|
||||
imports: [CommonModule, FormsModule, ChartComponent, ProfileListComponent, ProfileCreateComponent],
|
||||
imports: [CommonModule, FormsModule, ChartComponent, ProfileListComponent, ProfileCreateComponent, StatsBarComponent],
|
||||
templateUrl: './dashboard.component.html',
|
||||
styleUrls: ['./dashboard.component.css']
|
||||
})
|
||||
|
|
|
|||
80
ui/src/app/stats-bar.component.ts
Normal file
80
ui/src/app/stats-bar.component.ts
Normal file
|
|
@ -0,0 +1,80 @@
|
|||
import { Component, Input, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
|
||||
@Component({
|
||||
selector: 'snider-mining-stats-bar',
|
||||
standalone: true,
|
||||
imports: [CommonModule],
|
||||
schemas: [CUSTOM_ELEMENTS_SCHEMA],
|
||||
template: `
|
||||
@if(stats) {
|
||||
<div class="stats-bar">
|
||||
<div class="stat-item">
|
||||
<span class="label">Hashrate:</span>
|
||||
<span class="value">{{ stats.hashrate?.total[0] | number:'1.0-2' }} H/s</span>
|
||||
</div>
|
||||
<div class="stat-item">
|
||||
<span class="label">Algorithm:</span>
|
||||
<span class="value">{{ stats.algo }}</span>
|
||||
</div>
|
||||
<div class="stat-item">
|
||||
<span class="label">Difficulty:</span>
|
||||
<span class="value">{{ stats.connection?.diff | number }}</span>
|
||||
</div>
|
||||
<div class="stat-item">
|
||||
<span class="label">Accepted:</span>
|
||||
<span class="value">{{ stats.results?.shares_good }}</span>
|
||||
</div>
|
||||
<div class="stat-item">
|
||||
<span class="label">Rejected:</span>
|
||||
<span class="value">{{ stats.connection?.rejected }}</span>
|
||||
</div>
|
||||
<div class="stat-item">
|
||||
<span class="label">Avg Time:</span>
|
||||
<span class="value">{{ stats.results?.avg_time | number }}s</span>
|
||||
</div>
|
||||
<div class="stat-item">
|
||||
<span class="label">Uptime:</span>
|
||||
<span class="value">{{ stats.uptime | number }}s</span>
|
||||
</div>
|
||||
<div class="stat-item">
|
||||
<span class="label">Pool Uptime:</span>
|
||||
<span class="value">{{ stats.connection?.uptime | number }}s</span>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
`,
|
||||
styles: [`
|
||||
.stats-bar {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(4, 1fr);
|
||||
gap: 0.5rem;
|
||||
padding: 0.5rem;
|
||||
background-color: #f9f9f9;
|
||||
border: 1px solid #eee;
|
||||
border-radius: 8px;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
.stat-item {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
background-color: #fff;
|
||||
padding: 0.5rem;
|
||||
border-radius: 6px;
|
||||
box-shadow: 0 2px 4px rgba(0,0,0,0.05);
|
||||
}
|
||||
.label {
|
||||
font-size: 0.8rem;
|
||||
color: #666;
|
||||
margin-bottom: 0.25rem;
|
||||
}
|
||||
.value {
|
||||
font-weight: bold;
|
||||
font-size: 1.1rem;
|
||||
}
|
||||
`]
|
||||
})
|
||||
export class StatsBarComponent {
|
||||
@Input() stats: any;
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue