Merge branch 'feat/33-frontend-plots'
Frontend plot See merge request team-raclette/project-softweng!14
This commit is contained in:
4
.gitignore
vendored
4
.gitignore
vendored
@@ -91,7 +91,11 @@ fabric.properties
|
||||
# Android studio 3.1+ serialized cache file
|
||||
.idea/caches/build_file_checksums.ser
|
||||
|
||||
# Do not add specific ide files
|
||||
.idea/*
|
||||
|
||||
config.json
|
||||
.env
|
||||
|
||||
# for local config
|
||||
setup_env.sh
|
||||
|
||||
@@ -1,19 +1,65 @@
|
||||
# web-app
|
||||
This is a web application that uses Vue.js and Chart.js to display data from a database. The data is fetched from the database using an API and displayed in a chart.
|
||||
|
||||
## Project setup
|
||||
## Usage
|
||||
The web page contains two buttons:
|
||||
- **New measurments**: fetch the data from the database and add it to the chart.
|
||||
- **Fetch measurments**: ask for a new measurement at the currrent time.
|
||||
|
||||
It has too 3 selectors:
|
||||
- **User**: select the user to fetch the data from.
|
||||
- **Room**: select the room to fetch the data from.
|
||||
- **Device**: select the device to fetch the data from.
|
||||
|
||||
The chart is updated when the web page is loaded with default values for the selectors.
|
||||
|
||||
The chart can be updated by clicking on the **New measurments** button after selecting the user, room and device. But, the application doesn't care if the combination of user, room and device is valid or not. It will just fetch the data from the database and plot it on the chart.
|
||||
|
||||
## Environment setup
|
||||
|
||||
Install Node.js version v22.15.0 from [Node.js](https://nodejs.org/en/download/releases/) (LTS version).
|
||||
|
||||
Verify the installation by running the following command in your terminal:
|
||||
```terminal
|
||||
node --version
|
||||
npm --version
|
||||
```
|
||||
With the following output:
|
||||
```result
|
||||
v22.15.0
|
||||
10.9.2
|
||||
```
|
||||
|
||||
Then install the project dependencies by running:
|
||||
```terminal
|
||||
npm install
|
||||
```
|
||||
|
||||
### Compiles and hot-reloads for development
|
||||
Setup the environment:
|
||||
|
||||
linux:
|
||||
```terminal
|
||||
export VUE_APP_API_KEY=your_api_key
|
||||
export VUE_APP_API_SECRET=your_api_secret
|
||||
```
|
||||
windows:
|
||||
```terminal
|
||||
# use wsl ...
|
||||
```
|
||||
|
||||
### Compile and run for development
|
||||
|
||||
```terminal
|
||||
npm run serve
|
||||
```
|
||||
|
||||
### Compiles and minifies for production
|
||||
```
|
||||
### Compile and minifie for production
|
||||
```terminal
|
||||
npm run build
|
||||
```
|
||||
|
||||
### Customize configuration
|
||||
See [Configuration Reference](https://cli.vuejs.org/config/).
|
||||
### Links
|
||||
See [Configuration Reference](https://cli.vuejs.org/config/).\
|
||||
See [Vue.js](https://vuejs.org/guide/introduction.html).\
|
||||
See [chartjs](https://www.chartjs.org/docs/latest/).\
|
||||
See [vue-chartjs](https://vue-chartjs.org/).
|
||||
|
||||
32
web-app/package-lock.json
generated
32
web-app/package-lock.json
generated
@@ -9,7 +9,8 @@
|
||||
"version": "0.1.0",
|
||||
"dependencies": {
|
||||
"axios": "^1.9.0",
|
||||
"chartjs": "^0.3.24",
|
||||
"chart.js": "^4.4.9",
|
||||
"chartjs-adapter-date-fns": "^3.0.0",
|
||||
"dotenv": "^16.5.0",
|
||||
"vue": "^3.2.13",
|
||||
"vue-chartjs": "^5.3.2",
|
||||
@@ -371,8 +372,7 @@
|
||||
"version": "0.3.4",
|
||||
"resolved": "https://registry.npmjs.org/@kurkle/color/-/color-0.3.4.tgz",
|
||||
"integrity": "sha512-M5UknZPHRu3DEDWoipU6sE8PdkZ6Z/S+v4dD+Ke8IaNlpdSQah50lz1KtcFBa2vsdOnwbbnxJwVM4wty6udA5w==",
|
||||
"license": "MIT",
|
||||
"peer": true
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@leichtgewicht/ip-codec": {
|
||||
"version": "2.0.5",
|
||||
@@ -2114,7 +2114,6 @@
|
||||
"resolved": "https://registry.npmjs.org/chart.js/-/chart.js-4.4.9.tgz",
|
||||
"integrity": "sha512-EyZ9wWKgpAU0fLJ43YAEIF8sr5F2W3LqbS40ZJyHIner2lY14ufqv2VMp69MAiZ2rpwxEUxEhIH/0U3xyRynxg==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@kurkle/color": "^0.3.0"
|
||||
},
|
||||
@@ -2122,11 +2121,15 @@
|
||||
"pnpm": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/chartjs": {
|
||||
"version": "0.3.24",
|
||||
"resolved": "https://registry.npmjs.org/chartjs/-/chartjs-0.3.24.tgz",
|
||||
"integrity": "sha512-h6G9qcDqmFYnSWqjWCzQMeOLiypS+pM6Fq2Rj7LPty8Kjx5yHonwwJ7oEHImZpQ2u9Pu36XGYfardvvBiQVrhg==",
|
||||
"license": "MIT"
|
||||
"node_modules/chartjs-adapter-date-fns": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/chartjs-adapter-date-fns/-/chartjs-adapter-date-fns-3.0.0.tgz",
|
||||
"integrity": "sha512-Rs3iEB3Q5pJ973J93OBTpnP7qoGwvq3nUnoMdtxO+9aoJof7UFcRbWcIDteXuYd1fgAvct/32T9qaLyLuZVwCg==",
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"chart.js": ">=2.8.0",
|
||||
"date-fns": ">=2.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/chokidar": {
|
||||
"version": "3.6.0",
|
||||
@@ -2904,6 +2907,17 @@
|
||||
"integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/date-fns": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/date-fns/-/date-fns-4.1.0.tgz",
|
||||
"integrity": "sha512-Ukq0owbQXxa/U3EGtsdVBkR1w7KOQ5gIBqdH2hkvknzZPYvBxb/aa6E8L7tmjFtkwZBu3UXBbjIgPo/Ez4xaNg==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/kossnocorp"
|
||||
}
|
||||
},
|
||||
"node_modules/debounce": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/debounce/-/debounce-1.2.1.tgz",
|
||||
|
||||
@@ -8,7 +8,8 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"axios": "^1.9.0",
|
||||
"chartjs": "^0.3.24",
|
||||
"chart.js": "^4.4.9",
|
||||
"chartjs-adapter-date-fns": "^3.0.0",
|
||||
"dotenv": "^16.5.0",
|
||||
"vue": "^3.2.13",
|
||||
"vue-chartjs": "^5.3.2",
|
||||
|
||||
@@ -9,24 +9,12 @@
|
||||
<div class="main-content">
|
||||
<!-- Left Sidebar with Controls -->
|
||||
<div class="sidebar">
|
||||
<ControlPanel
|
||||
:show-temperature.sync="showTemperature"
|
||||
:show-humidity.sync="showHumidity"
|
||||
@add-temperature="addTemperature"
|
||||
@refresh="refreshData"
|
||||
:manager="manager"
|
||||
/>
|
||||
<ControlPanel :manager="manager" />
|
||||
</div>
|
||||
|
||||
<!-- Right Side Chart Area -->
|
||||
<div class="chart-area">
|
||||
<ChartComponent
|
||||
:series="series"
|
||||
:show-temperature="showTemperature"
|
||||
:show-humidity="showHumidity"
|
||||
:loading="loading"
|
||||
:error="error"
|
||||
/>
|
||||
<ChartComponent :manager="manager" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -38,7 +26,7 @@ import ChartComponent from "./components/ChartComponent.vue";
|
||||
import ControlPanel from "./components/ControlPanel.vue";
|
||||
import { HttpClient } from "./Services/HttpClient";
|
||||
import { TimeSeriesManager } from "./Measures/TimeSeriesManager";
|
||||
import { URL, USERNAME, PASSWORD, USER, ROOM, DEVICE, APP_NAME } from "./const";
|
||||
import { URL, USERNAME, PASSWORD, APP_NAME } from "./const";
|
||||
import { Serie } from "./Measures/Serie";
|
||||
|
||||
let httpClient = new HttpClient(URL, USERNAME, PASSWORD);
|
||||
@@ -53,53 +41,8 @@ export default defineComponent({
|
||||
data() {
|
||||
return {
|
||||
manager,
|
||||
series: [] as any[],
|
||||
loading: true,
|
||||
error: undefined as string | undefined,
|
||||
showTemperature: true,
|
||||
showHumidity: true,
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
addTemperature() {
|
||||
// Implement your functionality here
|
||||
console.log("Add temperature clicked");
|
||||
manager
|
||||
.getNewValue(USER, ROOM, DEVICE)
|
||||
.then((result) => {})
|
||||
.catch((error) => {
|
||||
console.error("Error asking data:", error);
|
||||
this.error = "Failed to load data. Please try again later.";
|
||||
this.loading = false;
|
||||
});
|
||||
},
|
||||
|
||||
refreshData() {
|
||||
console.log("Refreshing data...");
|
||||
this.fetchData();
|
||||
},
|
||||
|
||||
fetchData() {
|
||||
this.loading = true;
|
||||
this.error = undefined;
|
||||
|
||||
manager
|
||||
.getTimeSeriesData(USER, ROOM, DEVICE)
|
||||
.then((result) => {
|
||||
this.series = result;
|
||||
this.loading = false;
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error("Error fetching data:", error);
|
||||
this.error = "Failed to load data. Please try again later.";
|
||||
this.loading = false;
|
||||
});
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
// Fetch data when component is mounted
|
||||
this.fetchData();
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
import { TEMPERATURE, HUMIDITY, TYPE, VALUE } from "../const";
|
||||
|
||||
import { Colors } from "./Utils";
|
||||
|
||||
export class Serie {
|
||||
private _type: string;
|
||||
private _data: { time: number; value: number }[];
|
||||
private _data: { time: number; value: Date }[];
|
||||
|
||||
private _user: string;
|
||||
private _room: string;
|
||||
@@ -10,7 +12,7 @@ export class Serie {
|
||||
|
||||
constructor(
|
||||
type: string,
|
||||
data: { time: number; value: number }[],
|
||||
data: { time: number; value: Date }[],
|
||||
user: string,
|
||||
room: string,
|
||||
device: string
|
||||
@@ -22,8 +24,14 @@ export class Serie {
|
||||
this._device = device;
|
||||
}
|
||||
|
||||
public getLabel(): string {
|
||||
return `${this._type} - ${this._user} - ${this._room} - ${this._device}`;
|
||||
public getLabel(): String {
|
||||
if (this._type === TEMPERATURE) {
|
||||
return "Temperature [°C]";
|
||||
} else if (this._type === HUMIDITY) {
|
||||
return "Humidity [%]";
|
||||
} else {
|
||||
return "Unknown";
|
||||
}
|
||||
}
|
||||
|
||||
public getSerie(): any {
|
||||
@@ -33,9 +41,10 @@ export class Serie {
|
||||
data: this._data.map((v: any) => {
|
||||
return { x: v.time, y: v.value };
|
||||
}),
|
||||
borderColor: "rgba(255, 99, 132, 1)",
|
||||
backgroundColor: "rgba(255, 99, 132, 0.2)",
|
||||
borderColor: Colors.BLUE,
|
||||
backgroundColor: Colors.BLUE,
|
||||
borderWidth: 1,
|
||||
yAxisID: TEMPERATURE,
|
||||
};
|
||||
} else if (this._type === HUMIDITY) {
|
||||
return {
|
||||
@@ -43,9 +52,21 @@ export class Serie {
|
||||
data: this._data.map((v: any) => {
|
||||
return { x: v.time, y: v.value };
|
||||
}),
|
||||
borderColor: "rgba(54, 162, 235, 1)",
|
||||
backgroundColor: "rgba(54, 162, 235, 0.2)",
|
||||
borderColor: Colors.GREEN,
|
||||
backgroundColor: Colors.GREEN,
|
||||
borderWidth: 1,
|
||||
yAxisID: HUMIDITY,
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
label: "Unknown",
|
||||
data: this._data.map((v: any) => {
|
||||
return { x: v.time, y: v.value };
|
||||
}),
|
||||
borderColor: Colors.RED,
|
||||
backgroundColor: Colors.RED,
|
||||
borderWidth: 1,
|
||||
yAxisID: TEMPERATURE,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,12 +12,12 @@ export class TimeSeriesManager {
|
||||
tag: "remi",
|
||||
};
|
||||
selected_room = {
|
||||
room: "Bedroom",
|
||||
tag: "Bedroom",
|
||||
room: "Terrasse",
|
||||
tag: "Terrasse",
|
||||
};
|
||||
selected_device = {
|
||||
device: "Door sensor",
|
||||
tag: "DoorSensor",
|
||||
device: "Shed",
|
||||
tag: "Shed",
|
||||
};
|
||||
|
||||
user_options = [
|
||||
@@ -57,16 +57,17 @@ export class TimeSeriesManager {
|
||||
},
|
||||
];
|
||||
|
||||
error = ref(false);
|
||||
loading = ref("");
|
||||
|
||||
series = ref<Serie[]>([]);
|
||||
|
||||
constructor(client: HttpClient) {
|
||||
this.client = client;
|
||||
}
|
||||
|
||||
async getTimeSeriesData(
|
||||
user: string,
|
||||
room: string,
|
||||
device: string
|
||||
): Promise<Serie[]> {
|
||||
return this.client
|
||||
async getTimeSeriesData() {
|
||||
this.client
|
||||
.getValues(
|
||||
this.selected_user.tag,
|
||||
this.selected_room.tag,
|
||||
@@ -112,20 +113,20 @@ export class TimeSeriesManager {
|
||||
const temperatureSerie = new Serie(
|
||||
TEMPERATURE,
|
||||
temperatureRecordsProcessed,
|
||||
user,
|
||||
room,
|
||||
device
|
||||
this.selected_user.user,
|
||||
this.selected_room.room,
|
||||
this.selected_device.device
|
||||
);
|
||||
|
||||
const humiditySerie = new Serie(
|
||||
HUMIDITY,
|
||||
humidityRecordProcessed,
|
||||
user,
|
||||
room,
|
||||
device
|
||||
this.selected_user.user,
|
||||
this.selected_room.room,
|
||||
this.selected_device.device
|
||||
);
|
||||
|
||||
return [temperatureSerie, humiditySerie];
|
||||
this.series.value = [temperatureSerie, humiditySerie];
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error("Error fetching time series data:", error);
|
||||
@@ -133,9 +134,15 @@ export class TimeSeriesManager {
|
||||
});
|
||||
}
|
||||
|
||||
async getNewValue(user: string, room: string, device: string) {
|
||||
this.client.newValue(user, room, device).catch((error) => {
|
||||
console.error("Error asking new values:", error);
|
||||
async getNewValue() {
|
||||
this.client
|
||||
.newValue(
|
||||
this.selected_user.user,
|
||||
this.selected_room.room,
|
||||
this.selected_device.device
|
||||
)
|
||||
.catch((error) => {
|
||||
console.error("Error asking new values:", this.selected_device.device);
|
||||
throw error;
|
||||
});
|
||||
}
|
||||
|
||||
18
web-app/src/Measures/Utils.ts
Normal file
18
web-app/src/Measures/Utils.ts
Normal file
@@ -0,0 +1,18 @@
|
||||
export const Colors = {
|
||||
RED: "rgb(255, 99, 132)", // Red
|
||||
LIGHT_RED: "rgba(255, 99, 132, 0.2)",
|
||||
|
||||
BLUE: "rgb(54, 162, 235)", // Blue
|
||||
LIGHT_BLUE: "rgba(54, 162, 235, 0.2)",
|
||||
|
||||
YELLOW: "rgb(255, 206, 86)", // Yellow
|
||||
LIGHT_YELLOW: "rgba(255, 206, 86, 0.2)",
|
||||
|
||||
GREEN: "rgb(56, 193, 114)", // Green
|
||||
DARK_GREEN: "rgb(45, 153, 91)",
|
||||
|
||||
ORANGE: "rgb(246, 153, 63)", // Orange
|
||||
DARK_ORANGE: "rgb(230, 126, 34)",
|
||||
|
||||
DARK_BLUE: "rgb(39, 121, 189)", // Dark Blue
|
||||
};
|
||||
@@ -1,8 +1,8 @@
|
||||
<!-- src/components/ChartComponent.vue -->
|
||||
<template>
|
||||
<div class="chart-wrapper">
|
||||
<div v-if="loading" class="loading-state">Loading data...</div>
|
||||
<div v-else-if="error" class="error-state">{{ error }}</div>
|
||||
<div v-if="manager.loading" class="loading-state">Loading data...</div>
|
||||
<div v-else-if="manager.error" class="error-state">{{ manager.error }}</div>
|
||||
<div v-else class="chart-container">
|
||||
<Scatter
|
||||
v-if="chartData.datasets.length > 0"
|
||||
@@ -12,6 +12,7 @@
|
||||
<div v-else class="no-data-state">No data to display</div>
|
||||
</div>
|
||||
</div>
|
||||
<br />
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
@@ -23,12 +24,25 @@ import {
|
||||
LineElement,
|
||||
Tooltip,
|
||||
Legend,
|
||||
TimeScale,
|
||||
ChartOptions,
|
||||
ScatterDataPoint,
|
||||
} from "chart.js";
|
||||
import "chartjs-adapter-date-fns"; // Import the date adapter
|
||||
import { Scatter } from "vue-chartjs";
|
||||
import { Serie } from "../Measures/Serie";
|
||||
import { TimeSeriesManager } from "../Measures/TimeSeriesManager";
|
||||
import { Colors } from "../Measures/Utils";
|
||||
|
||||
// Register Chart.js components
|
||||
ChartJS.register(LinearScale, PointElement, LineElement, Tooltip, Legend);
|
||||
ChartJS.register(
|
||||
LinearScale,
|
||||
PointElement,
|
||||
LineElement,
|
||||
Tooltip,
|
||||
Legend,
|
||||
TimeScale
|
||||
);
|
||||
|
||||
export default defineComponent({
|
||||
name: "ChartComponent",
|
||||
@@ -36,41 +50,87 @@ export default defineComponent({
|
||||
Scatter,
|
||||
},
|
||||
props: {
|
||||
series: {
|
||||
type: Array as PropType<Serie[]>, // Use PropType to specify array of Serie
|
||||
default: () => [],
|
||||
},
|
||||
showTemperature: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
showHumidity: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
loading: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
error: {
|
||||
type: String as PropType<string | undefined>,
|
||||
default: null,
|
||||
manager: {
|
||||
type: Object as PropType<TimeSeriesManager>,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
setup(props) {
|
||||
const chartData = computed(() => {
|
||||
let series_prepared = props.series.map((s: Serie) => {
|
||||
if ((props.manager as TimeSeriesManager).series.value as Serie[]) {
|
||||
let series_prepared = (props.manager.series.value as Serie[]).map(
|
||||
(s: Serie) => {
|
||||
return s.getSerie();
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
return {
|
||||
datasets: series_prepared,
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
datasets: [],
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
const chartOptions = {
|
||||
const chartOptions: ChartOptions<"scatter"> = {
|
||||
responsive: true,
|
||||
maintainAspectRatio: false,
|
||||
maintainAspectRatio: true,
|
||||
scales: {
|
||||
x: {
|
||||
type: "time",
|
||||
position: "bottom",
|
||||
title: {
|
||||
text: "Time",
|
||||
display: true,
|
||||
},
|
||||
time: {
|
||||
unit: "minute", // Adjust the unit as needed (e.g., "minute", "hour", "day")
|
||||
displayFormats: {
|
||||
second: "HH:mm:ss", // Format for seconds
|
||||
minute: "MMM-dd HH:mm", // Format for minutes
|
||||
hour: "MMM dd HH:mm", // Format for hours
|
||||
day: "MMM dd", // Format for days
|
||||
},
|
||||
},
|
||||
grid: {
|
||||
drawOnChartArea: true, // only want the grid lines for one axis to show up
|
||||
},
|
||||
},
|
||||
temperature: {
|
||||
type: "linear", // only linear but allow scale type registration. This allows extensions to exist solely for log scale for instance
|
||||
position: "left",
|
||||
title: {
|
||||
text: "Temperature [°C]",
|
||||
display: true,
|
||||
},
|
||||
ticks: {
|
||||
color: Colors.BLUE,
|
||||
},
|
||||
grid: {
|
||||
drawOnChartArea: true, // only want the grid lines for one axis to show up
|
||||
},
|
||||
min: -10,
|
||||
max: 40,
|
||||
},
|
||||
humidity: {
|
||||
type: "linear", // only linear but allow scale type registration. This allows extensions to exist solely for log scale for instance
|
||||
position: "right",
|
||||
title: {
|
||||
text: "Humidity [%]",
|
||||
display: true,
|
||||
},
|
||||
ticks: {
|
||||
color: Colors.GREEN,
|
||||
},
|
||||
grid: {
|
||||
drawOnChartArea: true, // only want the grid lines for one axis to show up
|
||||
},
|
||||
min: 0,
|
||||
max: 100,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
return {
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
<template>
|
||||
<div class="control-panel">
|
||||
<button @click="$emit('add-temperature')" class="action-button">
|
||||
Add Temperature
|
||||
<button @click="newMeasurments" class="action-button">
|
||||
New Measurments
|
||||
</button>
|
||||
|
||||
<button @click="$emit('refresh')" class="refresh-button">
|
||||
<span class="button-icon">↻</span> Refresh Data
|
||||
<button @click="fetchData" class="refresh-button">
|
||||
Fetch Measurments
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@@ -57,40 +57,41 @@ import "vue-multiselect/dist/vue-multiselect.css"; // Add
|
||||
import { ref } from "vue";
|
||||
import { TimeSeriesManager } from "@/Measures/TimeSeriesManager";
|
||||
|
||||
let options = [{ code: "CA", country: "Canada" }];
|
||||
|
||||
|
||||
export default defineComponent({
|
||||
name: "ControlPanel",
|
||||
props: {
|
||||
showTemperature: {
|
||||
type: Boolean,
|
||||
required: true,
|
||||
},
|
||||
showHumidity: {
|
||||
type: Boolean,
|
||||
required: true,
|
||||
},
|
||||
manager: {
|
||||
type: TimeSeriesManager,
|
||||
required: true,
|
||||
}
|
||||
|
||||
},
|
||||
emits: [
|
||||
"add-temperature",
|
||||
"update:showTemperature",
|
||||
"update:showHumidity",
|
||||
"refresh",
|
||||
"simulate-data",
|
||||
],
|
||||
},
|
||||
components: {
|
||||
Multiselect,
|
||||
},
|
||||
methods: {
|
||||
setSelected(value: any) {
|
||||
// trigger a mutation, or dispatch an action
|
||||
newMeasurments() {
|
||||
// Implement your functionality here
|
||||
console.log("New measurments clicked");
|
||||
this.manager
|
||||
.getNewValue()
|
||||
.then((result) => {})
|
||||
.catch((error) => {
|
||||
console.error("Error asking data:", error);
|
||||
});
|
||||
},
|
||||
fetchData() {
|
||||
console.log("Fetch measurments clicked");
|
||||
this.manager
|
||||
.getTimeSeriesData()
|
||||
.then((result) => {})
|
||||
.catch((error) => {
|
||||
console.error("Error fetching data:", error);
|
||||
});
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.fetchData();
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
5
web-app/vue.config.js
Normal file
5
web-app/vue.config.js
Normal file
@@ -0,0 +1,5 @@
|
||||
module.exports = {
|
||||
devServer: {
|
||||
allowedHosts: 'all'
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user