mirror of
https://github.com/Start9Labs/start-os.git
synced 2026-03-26 02:11:53 +00:00
fix time display bug and type metrics (#2490)
* fix time display bug and type metrics * change metrics response * nullable temp * rename percentage used * match frontend types --------- Co-authored-by: Aiden McClelland <me@drbonez.dev>
This commit is contained in:
2
Makefile
2
Makefile
@@ -203,7 +203,7 @@ frontend/config.json: $(GIT_HASH_FILE) frontend/config-sample.json
|
||||
jq '.useMocks = false' frontend/config-sample.json | jq '.gitHash = "$(shell cat GIT_HASH.txt)"' > frontend/config.json
|
||||
|
||||
frontend/patchdb-ui-seed.json: frontend/package.json
|
||||
jq '."ack-welcome" = $(shell yq '.version' frontend/package.json)' frontend/patchdb-ui-seed.json > ui-seed.tmp
|
||||
jq '."ack-welcome" = $(shell jq '.version' frontend/package.json)' frontend/patchdb-ui-seed.json > ui-seed.tmp
|
||||
mv ui-seed.tmp frontend/patchdb-ui-seed.json
|
||||
|
||||
patch-db/client/node_modules: patch-db/client/package.json
|
||||
|
||||
@@ -360,60 +360,44 @@ impl<'de> Deserialize<'de> for GigaBytes {
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Serialize, Clone, Debug)]
|
||||
#[serde(rename_all = "kebab-case")]
|
||||
pub struct MetricsGeneral {
|
||||
#[serde(rename = "Temperature")]
|
||||
temperature: Option<Celsius>,
|
||||
pub temperature: Option<Celsius>,
|
||||
}
|
||||
#[derive(Deserialize, Serialize, Clone, Debug)]
|
||||
#[serde(rename_all = "kebab-case")]
|
||||
pub struct MetricsMemory {
|
||||
#[serde(rename = "Percentage Used")]
|
||||
pub percentage_used: Percentage,
|
||||
#[serde(rename = "Total")]
|
||||
pub total: MebiBytes,
|
||||
#[serde(rename = "Available")]
|
||||
pub available: MebiBytes,
|
||||
#[serde(rename = "Used")]
|
||||
pub used: MebiBytes,
|
||||
#[serde(rename = "Swap Total")]
|
||||
pub swap_total: MebiBytes,
|
||||
#[serde(rename = "Swap Free")]
|
||||
pub swap_free: MebiBytes,
|
||||
#[serde(rename = "Swap Used")]
|
||||
pub swap_used: MebiBytes,
|
||||
pub zram_total: MebiBytes,
|
||||
pub zram_available: MebiBytes,
|
||||
pub zram_used: MebiBytes,
|
||||
}
|
||||
#[derive(Deserialize, Serialize, Clone, Debug)]
|
||||
#[serde(rename_all = "kebab-case")]
|
||||
pub struct MetricsCpu {
|
||||
#[serde(rename = "User Space")]
|
||||
user_space: Percentage,
|
||||
#[serde(rename = "Kernel Space")]
|
||||
kernel_space: Percentage,
|
||||
#[serde(rename = "I/O Wait")]
|
||||
wait: Percentage,
|
||||
#[serde(rename = "Idle")]
|
||||
percentage_used: Percentage,
|
||||
idle: Percentage,
|
||||
#[serde(rename = "Usage")]
|
||||
usage: Percentage,
|
||||
user_space: Percentage,
|
||||
kernel_space: Percentage,
|
||||
wait: Percentage,
|
||||
}
|
||||
#[derive(Deserialize, Serialize, Clone, Debug)]
|
||||
#[serde(rename_all = "kebab-case")]
|
||||
pub struct MetricsDisk {
|
||||
#[serde(rename = "Size")]
|
||||
size: GigaBytes,
|
||||
#[serde(rename = "Used")]
|
||||
percentage_used: Percentage,
|
||||
used: GigaBytes,
|
||||
#[serde(rename = "Available")]
|
||||
available: GigaBytes,
|
||||
#[serde(rename = "Percentage Used")]
|
||||
used_percentage: Percentage,
|
||||
capacity: GigaBytes,
|
||||
}
|
||||
#[derive(Deserialize, Serialize, Clone, Debug)]
|
||||
#[serde(rename_all = "kebab-case")]
|
||||
pub struct Metrics {
|
||||
#[serde(rename = "General")]
|
||||
general: MetricsGeneral,
|
||||
#[serde(rename = "Memory")]
|
||||
memory: MetricsMemory,
|
||||
#[serde(rename = "CPU")]
|
||||
cpu: MetricsCpu,
|
||||
#[serde(rename = "Disk")]
|
||||
disk: MetricsDisk,
|
||||
}
|
||||
|
||||
@@ -739,7 +723,7 @@ async fn get_cpu_info(last: &mut ProcStat) -> Result<MetricsCpu, Error> {
|
||||
kernel_space: Percentage((new.system() - last.system()) as f64 * 100.0 / total_diff as f64),
|
||||
idle: Percentage((new.idle - last.idle) as f64 * 100.0 / total_diff as f64),
|
||||
wait: Percentage((new.iowait - last.iowait) as f64 * 100.0 / total_diff as f64),
|
||||
usage: Percentage((new.used() - last.used()) as f64 * 100.0 / total_diff as f64),
|
||||
percentage_used: Percentage((new.used() - last.used()) as f64 * 100.0 / total_diff as f64),
|
||||
};
|
||||
*last = new;
|
||||
Ok(res)
|
||||
@@ -752,8 +736,8 @@ pub struct MemInfo {
|
||||
buffers: Option<u64>,
|
||||
cached: Option<u64>,
|
||||
slab: Option<u64>,
|
||||
swap_total: Option<u64>,
|
||||
swap_free: Option<u64>,
|
||||
zram_total: Option<u64>,
|
||||
zram_free: Option<u64>,
|
||||
}
|
||||
#[instrument(skip_all)]
|
||||
pub async fn get_mem_info() -> Result<MetricsMemory, Error> {
|
||||
@@ -765,8 +749,8 @@ pub async fn get_mem_info() -> Result<MetricsMemory, Error> {
|
||||
buffers: None,
|
||||
cached: None,
|
||||
slab: None,
|
||||
swap_total: None,
|
||||
swap_free: None,
|
||||
zram_total: None,
|
||||
zram_free: None,
|
||||
};
|
||||
fn get_num_kb(l: &str) -> Result<u64, Error> {
|
||||
let e = Error::new(
|
||||
@@ -791,8 +775,8 @@ pub async fn get_mem_info() -> Result<MetricsMemory, Error> {
|
||||
_ if entry.starts_with("Buffers") => mem_info.buffers = Some(get_num_kb(entry)?),
|
||||
_ if entry.starts_with("Cached") => mem_info.cached = Some(get_num_kb(entry)?),
|
||||
_ if entry.starts_with("Slab") => mem_info.slab = Some(get_num_kb(entry)?),
|
||||
_ if entry.starts_with("SwapTotal") => mem_info.swap_total = Some(get_num_kb(entry)?),
|
||||
_ if entry.starts_with("SwapFree") => mem_info.swap_free = Some(get_num_kb(entry)?),
|
||||
_ if entry.starts_with("SwapTotal") => mem_info.zram_total = Some(get_num_kb(entry)?),
|
||||
_ if entry.starts_with("SwapFree") => mem_info.zram_free = Some(get_num_kb(entry)?),
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
@@ -808,24 +792,24 @@ pub async fn get_mem_info() -> Result<MetricsMemory, Error> {
|
||||
let buffers = ensure_present(mem_info.buffers, "Buffers")?;
|
||||
let cached = ensure_present(mem_info.cached, "Cached")?;
|
||||
let slab = ensure_present(mem_info.slab, "Slab")?;
|
||||
let swap_total_k = ensure_present(mem_info.swap_total, "SwapTotal")?;
|
||||
let swap_free_k = ensure_present(mem_info.swap_free, "SwapFree")?;
|
||||
let zram_total_k = ensure_present(mem_info.zram_total, "SwapTotal")?;
|
||||
let zram_free_k = ensure_present(mem_info.zram_free, "SwapFree")?;
|
||||
|
||||
let total = MebiBytes(mem_total as f64 / 1024.0);
|
||||
let available = MebiBytes(mem_available as f64 / 1024.0);
|
||||
let used = MebiBytes((mem_total - mem_free - buffers - cached - slab) as f64 / 1024.0);
|
||||
let swap_total = MebiBytes(swap_total_k as f64 / 1024.0);
|
||||
let swap_free = MebiBytes(swap_free_k as f64 / 1024.0);
|
||||
let swap_used = MebiBytes((swap_total_k - swap_free_k) as f64 / 1024.0);
|
||||
let zram_total = MebiBytes(zram_total_k as f64 / 1024.0);
|
||||
let zram_available = MebiBytes(zram_free_k as f64 / 1024.0);
|
||||
let zram_used = MebiBytes((zram_total_k - zram_free_k) as f64 / 1024.0);
|
||||
let percentage_used = Percentage((total.0 - available.0) / total.0 * 100.0);
|
||||
Ok(MetricsMemory {
|
||||
percentage_used,
|
||||
total,
|
||||
available,
|
||||
used,
|
||||
swap_total,
|
||||
swap_free,
|
||||
swap_used,
|
||||
zram_total,
|
||||
zram_available,
|
||||
zram_used,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -849,10 +833,10 @@ async fn get_disk_info() -> Result<MetricsDisk, Error> {
|
||||
let total_percentage = total_used as f64 / total_size as f64 * 100.0f64;
|
||||
|
||||
Ok(MetricsDisk {
|
||||
size: GigaBytes(total_size as f64 / 1_000_000_000.0),
|
||||
capacity: GigaBytes(total_size as f64 / 1_000_000_000.0),
|
||||
used: GigaBytes(total_used as f64 / 1_000_000_000.0),
|
||||
available: GigaBytes(total_available as f64 / 1_000_000_000.0),
|
||||
used_percentage: Percentage(total_percentage as f64),
|
||||
percentage_used: Percentage(total_percentage as f64),
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -11,15 +11,11 @@
|
||||
</ion-header>
|
||||
|
||||
<ion-content class="ion-padding with-widgets">
|
||||
<skeleton-list *ngIf="loading" [groups]="2"></skeleton-list>
|
||||
|
||||
<div id="metricSection">
|
||||
<ng-container *ngIf="!loading">
|
||||
<ion-item-group>
|
||||
<!-- <ion-item-divider>Time</ion-item-divider> -->
|
||||
<ion-item *ngIf="now$ | async as now; else timeLoading">
|
||||
<ion-item>
|
||||
<ion-label>
|
||||
<h1>System Time</h1>
|
||||
<ng-container *ngIf="now$ | async as now; else timeLoading">
|
||||
<h2>
|
||||
<ion-text style="color: white">
|
||||
<b>{{ now.value | date:'MMMM d, y, h:mm a z':'UTC' }}</b>
|
||||
@@ -30,25 +26,20 @@
|
||||
NTP not synced, time could be wrong
|
||||
</ion-text>
|
||||
</p>
|
||||
</ion-label>
|
||||
<ion-note slot="end" class="metric-note"></ion-note>
|
||||
</ion-item>
|
||||
</ng-container>
|
||||
<ng-template #timeLoading>
|
||||
<ion-item>
|
||||
<ion-label>
|
||||
<h1>System Time</h1>
|
||||
<p>Loading...</p>
|
||||
<h2>Loading...</h2>
|
||||
</ng-template>
|
||||
</ion-label>
|
||||
<ion-note slot="end" class="metric-note"></ion-note>
|
||||
</ion-item>
|
||||
</ng-template>
|
||||
|
||||
<ion-item>
|
||||
<ion-label>
|
||||
<h1>System Uptime</h1>
|
||||
<h2>
|
||||
<ion-text style="color: white">
|
||||
<ng-container *ngIf="uptime$ | async as uptime">
|
||||
<ng-container *ngIf="uptime$ | async as uptime; else uptimeLoading">
|
||||
<b>{{ uptime.days }}</b>
|
||||
Days,
|
||||
<b>{{ uptime.hours }}</b>
|
||||
@@ -58,27 +49,117 @@
|
||||
<b>{{ uptime.seconds }}</b>
|
||||
Seconds
|
||||
</ng-container>
|
||||
<ng-template #uptimeLoading>Loading...</ng-template>
|
||||
</ion-text>
|
||||
</h2>
|
||||
</ion-label>
|
||||
</ion-item>
|
||||
</ion-item-group>
|
||||
|
||||
<ion-item-group
|
||||
*ngFor="let metricGroup of metrics | keyvalue : asIsOrder"
|
||||
>
|
||||
<ion-item-divider>{{ metricGroup.key }}</ion-item-divider>
|
||||
<ion-item
|
||||
*ngFor="let metric of metricGroup.value | keyvalue : asIsOrder"
|
||||
>
|
||||
<ion-label>{{ metric.key }}</ion-label>
|
||||
<ion-note *ngIf="metric.value" slot="end" class="metric-note">
|
||||
<ion-text style="color: white">
|
||||
{{ metric.value.value }} {{ metric.value.unit }}
|
||||
</ion-text>
|
||||
<ng-container *ngIf="metrics$ | async as metrics; else loading">
|
||||
<ion-item-group *ngIf="metrics.general as general">
|
||||
<ion-item-divider>General</ion-item-divider>
|
||||
<ion-item>
|
||||
<ion-label>Temperature</ion-label>
|
||||
<ion-note slot="end">
|
||||
<ng-container *ngIf="general.temperature; else noTemp">
|
||||
{{ general.temperature.value }} °C
|
||||
</ng-container>
|
||||
<ng-template #noTemp>N/A</ng-template>
|
||||
</ion-note>
|
||||
</ion-item>
|
||||
</ion-item-group>
|
||||
|
||||
<ion-item-group *ngIf="metrics.memory as memory">
|
||||
<ion-item-divider>Memory</ion-item-divider>
|
||||
<ion-item>
|
||||
<ion-label>Percentage Used</ion-label>
|
||||
<ion-note slot="end">{{ memory['percentage-used'].value }} %</ion-note>
|
||||
</ion-item>
|
||||
<ion-item>
|
||||
<ion-label>Total</ion-label>
|
||||
<ion-note slot="end">
|
||||
<ion-text>{{ memory.total.value }} MiB</ion-text>
|
||||
</ion-note>
|
||||
</ion-item>
|
||||
<ion-item>
|
||||
<ion-label>Used</ion-label>
|
||||
<ion-note slot="end">
|
||||
<ion-text>{{ memory.used.value }} MiB</ion-text>
|
||||
</ion-note>
|
||||
</ion-item>
|
||||
<ion-item>
|
||||
<ion-label>Available</ion-label>
|
||||
<ion-note slot="end">{{ memory.available.value }} MiB</ion-note>
|
||||
</ion-item>
|
||||
<ion-item>
|
||||
<ion-label>zram Used</ion-label>
|
||||
<ion-note slot="end">{{ memory['zram-used'].value }} MiB</ion-note>
|
||||
</ion-item>
|
||||
<ion-item>
|
||||
<ion-label>zram Total</ion-label>
|
||||
<ion-note slot="end">{{ memory['zram-total'].value }} MiB</ion-note>
|
||||
</ion-item>
|
||||
<ion-item>
|
||||
<ion-label>zram Available</ion-label>
|
||||
<ion-note slot="end">{{ memory['zram-available'].value }} MiB</ion-note>
|
||||
</ion-item>
|
||||
</ion-item-group>
|
||||
|
||||
<ion-item-group *ngIf="metrics.cpu as cpu">
|
||||
<ion-item-divider>CPU</ion-item-divider>
|
||||
<ion-item>
|
||||
<ion-label>Percentage Used</ion-label>
|
||||
<ion-note slot="end">{{ cpu['percentage-used'].value }} %</ion-note>
|
||||
</ion-item>
|
||||
<ion-item>
|
||||
<ion-label>User Space</ion-label>
|
||||
<ion-note slot="end">
|
||||
<ion-text>{{ cpu['user-space'].value }} %</ion-text>
|
||||
</ion-note>
|
||||
</ion-item>
|
||||
<ion-item>
|
||||
<ion-label>Kernel Space</ion-label>
|
||||
<ion-note slot="end">
|
||||
<ion-text>{{ cpu['kernel-space'].value }} %</ion-text>
|
||||
</ion-note>
|
||||
</ion-item>
|
||||
<ion-item>
|
||||
<ion-label>Idle</ion-label>
|
||||
<ion-note slot="end">{{ cpu.idle.value }} %</ion-note>
|
||||
</ion-item>
|
||||
<ion-item>
|
||||
<ion-label>I/O Wait</ion-label>
|
||||
<ion-note slot="end">{{ cpu.wait.value }} %</ion-note>
|
||||
</ion-item>
|
||||
</ion-item-group>
|
||||
|
||||
<ion-item-group *ngIf="metrics.disk as disk">
|
||||
<ion-item-divider>Disk</ion-item-divider>
|
||||
<ion-item>
|
||||
<ion-label>Percentage Used</ion-label>
|
||||
<ion-note slot="end">{{ disk['percentage-used'].value }} %</ion-note>
|
||||
</ion-item>
|
||||
<ion-item>
|
||||
<ion-label>Capacity</ion-label>
|
||||
<ion-note slot="end">
|
||||
<ion-text>{{ disk.capacity.value }} GB</ion-text>
|
||||
</ion-note>
|
||||
</ion-item>
|
||||
<ion-item>
|
||||
<ion-label>Used</ion-label>
|
||||
<ion-note slot="end">
|
||||
<ion-text>{{ disk.used.value }} GB</ion-text>
|
||||
</ion-note>
|
||||
</ion-item>
|
||||
<ion-item>
|
||||
<ion-label>Available</ion-label>
|
||||
<ion-note slot="end">{{ disk.available.value }} GB</ion-note>
|
||||
</ion-item>
|
||||
</ion-item-group>
|
||||
</ng-container>
|
||||
</div>
|
||||
|
||||
<ng-template #loading>
|
||||
<skeleton-list [groups]="4"></skeleton-list>
|
||||
</ng-template>
|
||||
</ion-content>
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
.metric-note {
|
||||
ion-note {
|
||||
font-size: 16px;
|
||||
color: white;
|
||||
}
|
||||
@@ -3,6 +3,7 @@ import { Metrics } from 'src/app/services/api/api.types'
|
||||
import { ApiService } from 'src/app/services/api/embassy-api.service'
|
||||
import { TimeService } from 'src/app/services/time-service'
|
||||
import { pauseFor, ErrorToastService } from '@start9labs/shared'
|
||||
import { Subject } from 'rxjs'
|
||||
|
||||
@Component({
|
||||
selector: 'server-metrics',
|
||||
@@ -10,9 +11,8 @@ import { pauseFor, ErrorToastService } from '@start9labs/shared'
|
||||
styleUrls: ['./server-metrics.page.scss'],
|
||||
})
|
||||
export class ServerMetricsPage {
|
||||
loading = true
|
||||
going = false
|
||||
metrics: Metrics = {}
|
||||
metrics$ = new Subject<Metrics>()
|
||||
|
||||
readonly now$ = this.timeService.now$
|
||||
readonly uptime$ = this.timeService.uptime$
|
||||
@@ -25,19 +25,7 @@ export class ServerMetricsPage {
|
||||
|
||||
async ngOnInit() {
|
||||
await this.getMetrics()
|
||||
let headersCount = 0
|
||||
let rowsCount = 0
|
||||
Object.values(this.metrics).forEach(groupVal => {
|
||||
headersCount++
|
||||
Object.keys(groupVal).forEach(_ => {
|
||||
rowsCount++
|
||||
})
|
||||
})
|
||||
const height = headersCount * 54 + rowsCount * 50 + 24 // extra 24 for room at the bottom
|
||||
const elem = document.getElementById('metricSection')
|
||||
if (elem) elem.style.height = `${height}px`
|
||||
this.startDaemon()
|
||||
this.loading = false
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
@@ -59,7 +47,8 @@ export class ServerMetricsPage {
|
||||
|
||||
private async getMetrics(): Promise<void> {
|
||||
try {
|
||||
this.metrics = await this.embassyApi.getServerMetrics({})
|
||||
const metrics = await this.embassyApi.getServerMetrics({})
|
||||
this.metrics$.next(metrics)
|
||||
} catch (e: any) {
|
||||
this.errToast.present(e)
|
||||
this.stopDaemon()
|
||||
|
||||
@@ -835,85 +835,79 @@ export module Mock {
|
||||
|
||||
export function getServerMetrics() {
|
||||
return {
|
||||
Group1: {
|
||||
Metric1: {
|
||||
value: Math.random(),
|
||||
unit: 'mi/b',
|
||||
general: {
|
||||
temperature: {
|
||||
value: '66.8',
|
||||
unit: '°C',
|
||||
},
|
||||
Metric2: {
|
||||
value: Math.random(),
|
||||
},
|
||||
memory: {
|
||||
'percentage-used': {
|
||||
value: '30.7',
|
||||
unit: '%',
|
||||
},
|
||||
Metric3: {
|
||||
value: 10.1,
|
||||
total: {
|
||||
value: '31971.10',
|
||||
unit: 'MiB',
|
||||
},
|
||||
available: {
|
||||
value: '22150.66',
|
||||
unit: 'MiB',
|
||||
},
|
||||
used: {
|
||||
value: '8784.97',
|
||||
unit: 'MiB',
|
||||
},
|
||||
'zram-total': {
|
||||
value: '7992.00',
|
||||
unit: 'MiB',
|
||||
},
|
||||
'zram-available': {
|
||||
value: '7882.50',
|
||||
unit: 'MiB',
|
||||
},
|
||||
'zram-used': {
|
||||
value: '109.50',
|
||||
unit: 'MiB',
|
||||
},
|
||||
},
|
||||
cpu: {
|
||||
'percentage-used': {
|
||||
value: '8.4',
|
||||
unit: '%',
|
||||
},
|
||||
'user-space': {
|
||||
value: '7.0',
|
||||
unit: '%',
|
||||
},
|
||||
'kernel-space': {
|
||||
value: '1.4',
|
||||
unit: '%',
|
||||
},
|
||||
wait: {
|
||||
value: '0.5',
|
||||
unit: '%',
|
||||
},
|
||||
idle: {
|
||||
value: '91.1',
|
||||
unit: '%',
|
||||
},
|
||||
},
|
||||
Group2: {
|
||||
Hmmmm1: {
|
||||
value: 22.2,
|
||||
unit: 'mi/b',
|
||||
disk: {
|
||||
capacity: {
|
||||
value: '1851.60',
|
||||
unit: 'GB',
|
||||
},
|
||||
Hmmmm2: {
|
||||
value: 50,
|
||||
unit: '%',
|
||||
used: {
|
||||
value: '859.02',
|
||||
unit: 'GB',
|
||||
},
|
||||
Hmmmm3: {
|
||||
value: 10.1,
|
||||
unit: '%',
|
||||
available: {
|
||||
value: '992.59',
|
||||
unit: 'GB',
|
||||
},
|
||||
},
|
||||
Group3: {
|
||||
Hmmmm1: {
|
||||
value: Math.random(),
|
||||
unit: 'mi/b',
|
||||
},
|
||||
Hmmmm2: {
|
||||
value: 50,
|
||||
unit: '%',
|
||||
},
|
||||
Hmmmm3: {
|
||||
value: 10.1,
|
||||
unit: '%',
|
||||
},
|
||||
},
|
||||
Group4: {
|
||||
Hmmmm1: {
|
||||
value: Math.random(),
|
||||
unit: 'mi/b',
|
||||
},
|
||||
Hmmmm2: {
|
||||
value: 50,
|
||||
unit: '%',
|
||||
},
|
||||
Hmmmm3: {
|
||||
value: 10.1,
|
||||
unit: '%',
|
||||
},
|
||||
},
|
||||
Group5: {
|
||||
Hmmmm1: {
|
||||
value: Math.random(),
|
||||
unit: 'mi/b',
|
||||
},
|
||||
Hmmmm2: {
|
||||
value: 50,
|
||||
unit: '%',
|
||||
},
|
||||
Hmmmm3: {
|
||||
value: 10.1,
|
||||
unit: '%',
|
||||
},
|
||||
Hmmmm4: {
|
||||
value: Math.random(),
|
||||
unit: 'mi/b',
|
||||
},
|
||||
Hmmmm5: {
|
||||
value: 50,
|
||||
unit: '%',
|
||||
},
|
||||
Hmmmm6: {
|
||||
value: 10.1,
|
||||
'percentage-used': {
|
||||
value: '46.4',
|
||||
unit: '%',
|
||||
},
|
||||
},
|
||||
|
||||
@@ -301,12 +301,36 @@ export interface ActionResponse {
|
||||
qr: boolean
|
||||
}
|
||||
|
||||
interface MetricData {
|
||||
value: string
|
||||
unit: string
|
||||
}
|
||||
|
||||
export interface Metrics {
|
||||
[key: string]: {
|
||||
[key: string]: {
|
||||
value: string | number | null
|
||||
unit?: string
|
||||
general: {
|
||||
temperature: MetricData | null
|
||||
}
|
||||
memory: {
|
||||
total: MetricData
|
||||
'percentage-used': MetricData
|
||||
used: MetricData
|
||||
available: MetricData
|
||||
'zram-total': MetricData
|
||||
'zram-used': MetricData
|
||||
'zram-available': MetricData
|
||||
}
|
||||
cpu: {
|
||||
'percentage-used': MetricData
|
||||
idle: MetricData
|
||||
'user-space': MetricData
|
||||
'kernel-space': MetricData
|
||||
wait: MetricData
|
||||
}
|
||||
disk: {
|
||||
capacity: MetricData
|
||||
'percentage-used': MetricData
|
||||
used: MetricData
|
||||
available: MetricData
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3,13 +3,14 @@ import { map, shareReplay, startWith, switchMap } from 'rxjs/operators'
|
||||
import { PatchDB } from 'patch-db-client'
|
||||
import { DataModel } from './patch-db/data-model'
|
||||
import { ApiService } from './api/embassy-api.service'
|
||||
import { combineLatest, from, interval } from 'rxjs'
|
||||
import { combineLatest, interval, of } from 'rxjs'
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root',
|
||||
})
|
||||
export class TimeService {
|
||||
private readonly time$ = from(this.apiService.getSystemTime({})).pipe(
|
||||
private readonly time$ = of({}).pipe(
|
||||
switchMap(() => this.apiService.getSystemTime({})),
|
||||
switchMap(({ now, uptime }) => {
|
||||
const current = new Date(now).valueOf()
|
||||
return interval(1000).pipe(
|
||||
|
||||
Reference in New Issue
Block a user