diff --git a/Makefile b/Makefile index 583231f1b..625a4cec2 100644 --- a/Makefile +++ b/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 diff --git a/backend/src/system.rs b/backend/src/system.rs index 249ade9c3..989cdc4aa 100644 --- a/backend/src/system.rs +++ b/backend/src/system.rs @@ -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, + pub temperature: Option, } #[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 { 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, cached: Option, slab: Option, - swap_total: Option, - swap_free: Option, + zram_total: Option, + zram_free: Option, } #[instrument(skip_all)] pub async fn get_mem_info() -> Result { @@ -765,8 +749,8 @@ pub async fn get_mem_info() -> Result { 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 { let e = Error::new( @@ -791,8 +775,8 @@ pub async fn get_mem_info() -> Result { _ 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 { 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 { 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), }) } diff --git a/frontend/projects/ui/src/app/pages/server-routes/server-metrics/server-metrics.page.html b/frontend/projects/ui/src/app/pages/server-routes/server-metrics/server-metrics.page.html index 91b00fb28..0926334aa 100644 --- a/frontend/projects/ui/src/app/pages/server-routes/server-metrics/server-metrics.page.html +++ b/frontend/projects/ui/src/app/pages/server-routes/server-metrics/server-metrics.page.html @@ -11,74 +11,155 @@ - - -
- - - - - -

System Time

-

- - {{ now.value | date:'MMMM d, y, h:mm a z':'UTC' }} - -

-

- - NTP not synced, time could be wrong - -

-
- -
- - - -

System Time

-

Loading...

-
- -
-
- - - -

System Uptime

-

- - - {{ uptime.days }} - Days, - {{ uptime.hours }} - Hours, - {{ uptime.minutes }} - Minutes, - {{ uptime.seconds }} - Seconds - - -

-
-
-
- - - {{ metricGroup.key }} - - {{ metric.key }} - + + + +

System Time

+ +

- {{ metric.value.value }} {{ metric.value.unit }} + {{ now.value | date:'MMMM d, y, h:mm a z':'UTC' }} - - - - -

+ +

+ + NTP not synced, time could be wrong + +

+ + +

Loading...

+
+ + + + + + +

System Uptime

+

+ + + {{ uptime.days }} + Days, + {{ uptime.hours }} + Hours, + {{ uptime.minutes }} + Minutes, + {{ uptime.seconds }} + Seconds + + Loading... + +

+
+
+ + + + + General + + Temperature + + + {{ general.temperature.value }} °C + + N/A + + + + + + Memory + + Percentage Used + {{ memory['percentage-used'].value }} % + + + Total + + {{ memory.total.value }} MiB + + + + Used + + {{ memory.used.value }} MiB + + + + Available + {{ memory.available.value }} MiB + + + zram Used + {{ memory['zram-used'].value }} MiB + + + zram Total + {{ memory['zram-total'].value }} MiB + + + zram Available + {{ memory['zram-available'].value }} MiB + + + + + CPU + + Percentage Used + {{ cpu['percentage-used'].value }} % + + + User Space + + {{ cpu['user-space'].value }} % + + + + Kernel Space + + {{ cpu['kernel-space'].value }} % + + + + Idle + {{ cpu.idle.value }} % + + + I/O Wait + {{ cpu.wait.value }} % + + + + + Disk + + Percentage Used + {{ disk['percentage-used'].value }} % + + + Capacity + + {{ disk.capacity.value }} GB + + + + Used + + {{ disk.used.value }} GB + + + + Available + {{ disk.available.value }} GB + + + + + + +
diff --git a/frontend/projects/ui/src/app/pages/server-routes/server-metrics/server-metrics.page.scss b/frontend/projects/ui/src/app/pages/server-routes/server-metrics/server-metrics.page.scss index eea898305..36fb91260 100644 --- a/frontend/projects/ui/src/app/pages/server-routes/server-metrics/server-metrics.page.scss +++ b/frontend/projects/ui/src/app/pages/server-routes/server-metrics/server-metrics.page.scss @@ -1,3 +1,4 @@ -.metric-note { +ion-note { font-size: 16px; + color: white; } \ No newline at end of file diff --git a/frontend/projects/ui/src/app/pages/server-routes/server-metrics/server-metrics.page.ts b/frontend/projects/ui/src/app/pages/server-routes/server-metrics/server-metrics.page.ts index a4c2dc325..569d34a45 100644 --- a/frontend/projects/ui/src/app/pages/server-routes/server-metrics/server-metrics.page.ts +++ b/frontend/projects/ui/src/app/pages/server-routes/server-metrics/server-metrics.page.ts @@ -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() 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 { 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() diff --git a/frontend/projects/ui/src/app/services/api/api.fixures.ts b/frontend/projects/ui/src/app/services/api/api.fixures.ts index 5ab0460b1..67ddbd8d6 100644 --- a/frontend/projects/ui/src/app/services/api/api.fixures.ts +++ b/frontend/projects/ui/src/app/services/api/api.fixures.ts @@ -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: '%', }, }, diff --git a/frontend/projects/ui/src/app/services/api/api.types.ts b/frontend/projects/ui/src/app/services/api/api.types.ts index 860bc6003..9d804caf9 100644 --- a/frontend/projects/ui/src/app/services/api/api.types.ts +++ b/frontend/projects/ui/src/app/services/api/api.types.ts @@ -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 } } diff --git a/frontend/projects/ui/src/app/services/time-service.ts b/frontend/projects/ui/src/app/services/time-service.ts index 26d1a216b..641144dae 100644 --- a/frontend/projects/ui/src/app/services/time-service.ts +++ b/frontend/projects/ui/src/app/services/time-service.ts @@ -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(