Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
FROM node:16.7
ENV NODE_ENV=production

WORKDIR /app

COPY ["package.json", "package-lock.json*", "./"]

RUN npm install --production

COPY . .

CMD [ "/app/entrypoint.sh" ]
11 changes: 11 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
"axios": "^0.24.0",
"core-js": "^3.6.5",
"vue": "^2.6.11",
"vue-router": "^3.5.3",
"vue-google-charts": "^0.3.3",
"vue2-datepicker": "^3.10.3"
},
Expand Down
174 changes: 36 additions & 138 deletions src/App.vue
Original file line number Diff line number Diff line change
Expand Up @@ -3,143 +3,39 @@
<img alt="Vue logo" src="./assets/cars.svg" />
<h1>Happy Cars</h1>

<div class="form">
<SelectionInput
label="Choose a car:"
:selected="selectedCar"
:values="cars"
v-on:change-value="(value) => changeValue('selectedCar', value)"
/>

<SelectionInput
label="Choose a sensor:"
:selected="selectedSensor"
:values="availableSensors"
v-on:change-value="(value) => changeValue('selectedSensor', value)"
/>
<div class="input">
<label>Start time: </label>
<date-picker
v-model="selectedStartTime"
v-on:change="(value) => changeValue('selectedStartTime', value)"
valueType="date"
type="datetime"
></date-picker>
</div>
<div class="input">
<label>End time: </label>
<date-picker
v-model="selectedEndTime"
v-on:change="(value) => changeValue('selectedEndTime', value)"
valueType="date"
type="datetime"
></date-picker>
<div class="mx-changepanel container">
<div class="mx-input-wrapper">
<button class="mx-input button" v-on:click="changePanel">
Get statistics
</button>
</div>
</div>
<div class="data-container">
<template v-if="data">
<DownloadData :data="data" />
<h2>Chart</h2>
<LineChart :chartData="data" />
<h2>Table</h2>
<TableChart :chartData="data" />
</template>
<template v-else>
<h1>😔</h1>
<h2>No data available</h2>
</template>
</div>

<DataPanel v-if="dataPanel"/>
<Statistics v-else/>
</div>
</template>

<script>
import LineChart from "./components/LineChart.vue";
import TableChart from "./components/TableChart.vue";
import DownloadData from "./components/DownloadData.vue";
import DatePicker from "vue2-datepicker";
import "vue2-datepicker/index.css";

import SelectionInput from "./components/SelectionInput.vue";
import ApiClient from "./services/ApiClient";
import DataPanel from "./components/DataPanel.vue";
import Statistics from "./components/Statistics.vue";

export default {
name: "App",
components: {
LineChart,
TableChart,
SelectionInput,
DatePicker,
DownloadData,
},
data() {
let selectedStartTime = new Date(Date.now());
selectedStartTime.setMinutes(selectedStartTime.getMinutes() - 1);
let selectedEndTime = new Date(Date.now());
return {
loading: true,
availableSensors: [
{ name: "Speed", id: "speed" },
{ name: "Accelerometer", id: "accel" },
{ name: "Engine", id: "engine" },
{ name: "Temperature", id: "temperature" },
],
cars: [],
data: null,
selectedStartTime: selectedStartTime,
selectedEndTime: selectedEndTime,
selectedCar: null,
selectedSensor: "speed",
dataPanel: true,
};
},
created() {
this.fetchCars();
components: {
DataPanel,
Statistics
},
methods: {
changeValue(fieldName, value) {
console.log(value);
this[fieldName] = value;
if (this.selectedSensor && this.selectedCar) {
this.fetchSensorData();
}
},

async fetchCars() {
this.loading = true;
this.cars = await ApiClient.instance.getCars();
this.selectedCar = this.cars[0].id;
console.log(this.cars[0].id);
this.fetchSensorData();
this.loading = false;
},

async fetchSensorData() {
this.loading = true;
let data = await ApiClient.instance.getSensorDate(
this.selectedSensor,
this.selectedCar,
this.selectedStartTime.toISOString(),
this.selectedEndTime.toISOString()
);
console.log("data");
console.log(data);
if (data.length > 0) {
this.data = [
[
"Time",
this.availableSensors.find((x) => x.id === this.selectedSensor)
.name,
],
];
data.map((x) =>
this.data.push([new Date(x.createDate).toLocaleString().replaceAll(",", ""), x.value])
);
console.log(this.data);
} else {
this.data = null;
}
this.loading = false;
},
},
changePanel() {
this.dataPanel = !this.dataPanel;
}
}
};
</script>

Expand All @@ -159,16 +55,6 @@ label {
padding-right: 0.5rem;
}

.form {
margin-top: 3rem;
}

.data-container {
display: flex;
flex-direction: column;
justify-content: center;
}

h1 {
font-size: 3rem;
}
Expand All @@ -178,14 +64,26 @@ h2 {
margin-top: 4rem;
}

.table-title {
margin-top: 4rem;
.mx-changepanel.container {
align-self: center;
margin-top: 2rem;
display: flex;
flex-direction: column;
justify-content: center;
}

.input {
margin: 0.5rem;
display: flex;
align-items: center;
.button.mx-input {
box-shadow: 0 0 16px lightgray;
background-color: rgb(68, 110, 142);
padding-right: 10px;
color: white;
border: none;
}

.button.mx-input:hover {
box-shadow: 0 0 16px grey;
background-color: rgb(58, 95, 124);
cursor: pointer;
}

#app > img {
Expand Down
2 changes: 1 addition & 1 deletion src/components/TableChart.vue
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ tr.google-visualization-table-tr-odd {
th.google-visualization-table-tr,
td.google-visualization-table-td {
border: 1px solid gainsboro;
min-width: 200px;
min-width: 150px;
}

</style>
8 changes: 8 additions & 0 deletions src/services/ApiClient.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,14 @@ class ApiClient {
}
return [];
}

async getStatistics(carId) {
const result = await this.#axiosInstance.get(`api/${carId}/stats`);
if (result.data) {
return result.data;
}
return [];
}
}

export default ApiClient;