Skip to content

Commit

Permalink
frontend: usage: Adjust chart scale and last usage
Browse files Browse the repository at this point in the history
* Adjust chart scale to automatic update to better unit (B, KB, MB, GB)
* Adjust last usage to continue till reset date
* Move levelToBytes and bytesToLevel to utils
  • Loading branch information
JoaoMario109 authored and patrickelectric committed Dec 10, 2024
1 parent 1f65027 commit d838e1b
Show file tree
Hide file tree
Showing 4 changed files with 135 additions and 87 deletions.
35 changes: 4 additions & 31 deletions frontend/src/components/usage/UsageControls.vue
Original file line number Diff line number Diff line change
Expand Up @@ -55,11 +55,12 @@
</template>

<script setup lang="ts">
import { ref, watch } from 'vue';
import { defineProps } from 'vue';
import { defineProps, ref, watch } from 'vue';
import { ModemDevice, DataUsageSettings, DataUsageControls } from '@/types/ModemManager';
import { DataUsageControls, DataUsageSettings, ModemDevice } from '@/types/ModemManager';
import { bytesToLevel, levelToBytes } from '@/utils';
/** Props / Emits */
const props = defineProps<{
modem: ModemDevice;
dataUsage: DataUsageSettings | null;
Expand All @@ -78,34 +79,6 @@ const resetDayRules = [
(v: number) => v >= 1 && v <= 31 || "Day must be between 1 and 31",
];
/** Utils */
const bytesToLevel = (bytes: number): [number, string] => {
if (bytes < 2 ** 10) {
return [bytes, "B"];
} else if (bytes < 2 ** 20) {
return [bytes / (2 ** 10), "KB"];
} else if (bytes < 2 ** 30) {
return [bytes / (2 ** 20), "MB"];
} else {
return [bytes / (2 ** 30), "GB"];
}
};
const levelToBytes = (level: number, unit: string): number => {
switch (unit) {
case "B":
return level;
case "KB":
return level * (2 ** 10);
case "MB":
return level * (2 ** 20);
case "GB":
return level * (2 ** 30);
default:
return 0;
}
};
/** Watchers */
watch(() => props.dataUsage, (dataUsage) => {
if (!dataUsage) {
Expand Down
117 changes: 65 additions & 52 deletions frontend/src/components/usage/UsageDetails.vue
Original file line number Diff line number Diff line change
@@ -1,28 +1,30 @@
<template>
<v-card class="pa-4">
<v-card-text>
<apexchart
:options="chartOptions"
:series="usageChartData"
type="line"
/>
</v-card-text>
</v-card>
<v-card class="pa-4">
<v-card-text>
<apexchart
:options="chartOptions"
:series="chartData"
type="line"
/>
</v-card-text>
</v-card>
</template>

<script setup lang="ts">
import { defineProps, computed } from 'vue';
import { computed, defineProps } from 'vue';
import dayjs from 'dayjs';
import { ModemDevice, DataUsageSettings } from '@/types/ModemManager';
import { DataUsageSettings, ModemDevice } from '@/types/ModemManager';
import { bytesToLevel, getBaseApexChartOptions } from '@/utils';
/** Props / Emits */
const props = defineProps<{
modem: ModemDevice;
dataUsage: DataUsageSettings | null;
}>();
/** Computed */
const usageChartData = computed(() => {
const chartPoints = computed(() => {
if (!props.dataUsage) {
return [
{
Expand All @@ -39,63 +41,74 @@ const usageChartData = computed(() => {
const endDate = startDate.add(1, 'month').add(1, 'day');
/** Create a date array from start to end date */
const data = [];
let lastUsage = 0;
for (let date = startDate; date.isBefore(endDate); date = date.add(1, 'day')) {
const usage = props.dataUsage.data_points[date.format('YYYY-MM-DD')]
if (usage) {
lastUsage = usage[0] + usage[1];
}
data.push({
x: date.format('YYYY-MM-DD'),
y: usage ?? lastUsage,
y: lastUsage,
});
}
return [
{
name: 'Usage',
data: data,
data,
},
];
});
const chartOptions = computed(() => ({
chart: { toolbar: { show: false } },
tooltip: { enabled: true },
dataLabels: { enabled: false },
yaxis: {
title: {
text: 'Data (GB)',
style: {
fontSize: '14px',
color: 'white'
}
const chartData = computed(() => {
const max = Math.max(...chartPoints.value[0].data.map((d: any) => d.y));
const [_, unit] = bytesToLevel(max);
console.log("Unit", unit);
return [
{
name: 'Usage',
data: chartPoints.value[0].data.map((d: any) => ({
x: d.x,
y: bytesToLevel(d.y, unit)[0].toFixed(1),
})),
},
},
xaxis: {
type: 'category',
categories: usageChartData.value[0]?.data.map(d => d.x), // Dynamically derive categories
title: {
text: 'Data Usage Since Last Reset',
style: {
fontSize: '14px',
color: 'white'
}
];
});
const chartOptions = computed(() => {
const max = Math.max(...chartPoints.value[0].data.map((d: any) => d.y));
const [_, unit] = bytesToLevel(max);
const data = chartPoints.value[0].data;
const firstDate = data[0]?.x;
const lastDate = data[data.length - 1]?.x;
const baseOptions = getBaseApexChartOptions(undefined, "Data usage since last reset", unit);
return {
...baseOptions,
xaxis: {
...baseOptions.xaxis,
labels: {
formatter: (value: string) => {
if (value === firstDate || value === lastDate) {
return value;
}
return "";
},
style: {
colors: 'white',
},
},
},
labels: {
rotate: -45, // Rotate for better visibility
}
},
grid: {
borderColor: '#444',
strokeDashArray: 5,
},
}));
}
})
</script>

<style scoped>
.v-card {
border: 1px solid #ccc;
border-radius: 8px;
}
</style>
15 changes: 11 additions & 4 deletions frontend/src/components/usage/UsageDetailsTab.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<template>
<v-container fluid class="d-flex flex-wrap">
<v-container v-if="modemDataUsage !== null" fluid class="d-flex flex-wrap">
<v-col cols="12" md="7">
<UsageDetails
:modem="modem"
Expand All @@ -14,14 +14,21 @@
/>
</v-col>
</v-container>
<SpinningLogo
v-else
size="50"
subtitle="Loading modem data usage..."
/>
</template>

<script setup lang="ts">
import { defineProps, onMounted, ref, watch } from 'vue';
import SpinningLogo from '@/components/common/SpinningLogo.vue';
import ModemManager from '@/services/ModemManager';
import { ModemDevice, DataUsageSettings, DataUsageControls } from '@/types/ModemManager';
import { DataUsageControls, DataUsageSettings, ModemDevice } from '@/types/ModemManager';
/** Props / Emits */
const props = defineProps<{
modem: ModemDevice;
}>();
Expand All @@ -35,7 +42,7 @@ const fetchDataUsage = async () => {
const data = await ModemManager.fetchDataUsageById(props.modem.id);
modemDataUsage.value = data;
} catch (error) {
console.error("Failed to fetch data usage", error);
console.error('Failed to fetch Data Usage info, error:', (error as any)?.message);
}
};
Expand All @@ -48,7 +55,7 @@ const onControlsUpdate = async (control: DataUsageControls) => {
const data = await ModemManager.setDataUsageControlById(props.modem.id, control);
modemDataUsage.value = data;
} catch (error) {
console.error("Failed to update data usage control", error);
console.error('Failed to update Data Usage control, error:', (error as any)?.message);
}
}
Expand Down
55 changes: 55 additions & 0 deletions frontend/src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -89,9 +89,64 @@ export const getBaseApexChartOptions = (
};
}

/**
* Converts bytes to a human-readable level
* @param {number} bytes The bytes to be converted
* @returns {[number, string]} The level and unit
*/
export const bytesToLevel = (bytes: number, unit?: string): [number, string] => {
if (unit) {
switch (unit) {
case "B":
return [bytes, "B"];
case "KB":
return [bytes / (2 ** 10), "KB"];
case "MB":
return [bytes / (2 ** 20), "MB"];
case "GB":
return [bytes / (2 ** 30), "GB"];
default:
return [bytes, "B"];
}
}

if (bytes < 2 ** 10) {
return [bytes, "B"];
} else if (bytes < 2 ** 20) {
return [bytes / (2 ** 10), "KB"];
} else if (bytes < 2 ** 30) {
return [bytes / (2 ** 20), "MB"];
} else {
return [bytes / (2 ** 30), "GB"];
}
};

/**
* Converts a level to bytes
* @param {number} level The level to be converted
* @param {string} unit The unit of the level
* @returns {number} The bytes
*/
export const levelToBytes = (level: number, unit: string): number => {
switch (unit) {
case "B":
return level;
case "KB":
return level * (2 ** 10);
case "MB":
return level * (2 ** 20);
case "GB":
return level * (2 ** 30);
default:
return 0;
}
};

export default {
sleep,
getUSBFromDevice,
getThumbnailFromProduct,
getBaseApexChartOptions,
bytesToLevel,
levelToBytes
}

0 comments on commit d838e1b

Please sign in to comment.