parent
709efb3f01
commit
b834899df4
After Width: | Height: | Size: 1.3 MiB |
@ -0,0 +1,7 @@
|
||||
/*
|
||||
* Replace this with your own classes
|
||||
*
|
||||
* e.g.
|
||||
* .container {
|
||||
* }
|
||||
*/
|
@ -0,0 +1,10 @@
|
||||
import { render } from '@testing-library/react';
|
||||
|
||||
import PotantialProblemeSensorsTable from './potantial-probleme-sensors-table';
|
||||
|
||||
describe('PotantialProblemeSensorsTable', () => {
|
||||
it('should render successfully', () => {
|
||||
const { baseElement } = render(<PotantialProblemeSensorsTable />);
|
||||
expect(baseElement).toBeTruthy();
|
||||
});
|
||||
});
|
@ -0,0 +1,191 @@
|
||||
import styles from './potantial-probleme-sensors-table.module.scss';
|
||||
import {Measures, Prisma} from "@weather-platform/prisma-clients/Measures";
|
||||
import axios from "axios";
|
||||
import {AGW_URL} from "../../../../agw";
|
||||
import {useEffect, useState} from "react";
|
||||
import AgregatorTableItem from "../agregator-table-item/agregator-table-item";
|
||||
import OK from './ok-status.gif';
|
||||
import { Chart as ChartJS, ArcElement, Tooltip, Legend } from 'chart.js';
|
||||
import { Pie } from 'react-chartjs-2';
|
||||
|
||||
/* eslint-disable-next-line */
|
||||
export interface PotantialProblemeSensorsTableProps {}
|
||||
|
||||
|
||||
ChartJS.register(ArcElement, Tooltip, Legend);
|
||||
|
||||
|
||||
export function PotantialProblemeSensorsTable(
|
||||
props: PotantialProblemeSensorsTableProps
|
||||
) {
|
||||
|
||||
const fetchGetMeasuresList = async (params: Prisma.MeasuresFindManyArgs = {}) => {
|
||||
try {
|
||||
const response = await axios.post( AGW_URL + '/api/v1/measures/get-with-params', params);
|
||||
const data = response.data;
|
||||
return data;
|
||||
} catch (error) {
|
||||
console.error('Error fetching data:', error);
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
const [measures, setMeasures] = useState<Measures[] | null>(null);
|
||||
|
||||
const twoHoursAgo = new Date(Date.now() - 2 * 60 * 60 * 1000);
|
||||
|
||||
const updateMeasureData = async () => {
|
||||
const response = await fetchGetMeasuresList({
|
||||
where: {
|
||||
sensor_uuid: {
|
||||
not: {
|
||||
in: [],
|
||||
},
|
||||
},
|
||||
time: {
|
||||
gte: twoHoursAgo.toISOString(),
|
||||
},
|
||||
},
|
||||
});
|
||||
if (response !== null) {
|
||||
setMeasures(response);
|
||||
}
|
||||
};
|
||||
|
||||
const [measuresCount, setMeasuresCount] = useState<number>(0);
|
||||
|
||||
const updateAllMeasureData = async () => {
|
||||
const response = await fetchGetMeasuresList({
|
||||
select: {
|
||||
uuid: true,
|
||||
}
|
||||
});
|
||||
if (response !== null) {
|
||||
setMeasuresCount(response.length);
|
||||
}
|
||||
};
|
||||
|
||||
function upd() {
|
||||
updateAllMeasureData();
|
||||
updateMeasureData();
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
upd();
|
||||
const interval = setInterval(upd, 5000);
|
||||
return () => clearInterval(interval);
|
||||
}, []);
|
||||
|
||||
const data = {
|
||||
labels: ['Fatal', 'Success'],
|
||||
datasets: [
|
||||
{
|
||||
label: '# of Votes',
|
||||
data: [measures?.length || 0, measuresCount],
|
||||
backgroundColor: [
|
||||
'rgba(255, 99, 132, 0.2)',
|
||||
'rgba(54, 162, 235, 0.2)',
|
||||
],
|
||||
borderColor: [
|
||||
'rgba(255, 99, 132, 1)',
|
||||
'rgba(54, 162, 235, 1)',
|
||||
],
|
||||
borderWidth: 1,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="w-full px-4">
|
||||
<h1 className={'text-center font-bold text-2xl'}>Incorect get data from Sensors</h1>
|
||||
<div className="px-4 py-4 sm:-mx-8 sm:px-8 w-full flex space-x-2">
|
||||
<div className="inline-block overflow-hidden rounded-lg shadow ring-1 ring-gray-100 w-3/4">
|
||||
<table className="min-w-full leading-normal">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col"
|
||||
className="px-5 py-3 text-sm font-normal text-left text-gray-800 uppercase bg-white border-b border-gray-200">
|
||||
Type / Value
|
||||
</th>
|
||||
<th scope="col"
|
||||
className="px-5 py-3 text-sm font-normal text-left text-gray-800 uppercase bg-white border-b border-gray-200">
|
||||
Last connection
|
||||
</th>
|
||||
<th scope="col"
|
||||
className="px-5 py-3 text-sm font-normal text-left text-gray-800 uppercase bg-white border-b border-gray-200">
|
||||
Sensor
|
||||
</th>
|
||||
<th scope="col"
|
||||
className="px-5 py-3 text-sm font-normal text-left text-gray-800 uppercase bg-white border-b border-gray-200">
|
||||
Created at
|
||||
</th>
|
||||
<th scope="col"
|
||||
className="px-5 py-3 text-sm font-normal text-left text-gray-800 uppercase bg-white border-b border-gray-200">
|
||||
status
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{
|
||||
measures?.map(
|
||||
(measure, key) => (
|
||||
<tr>
|
||||
<td className="px-5 py-5 text-sm bg-white border-b border-gray-200">
|
||||
<div className="ml-3">
|
||||
<p className="text-gray-900 whitespace-no-wrap">
|
||||
{ measure.type } / { measure.value }
|
||||
</p>
|
||||
</div>
|
||||
</td>
|
||||
<td className="px-5 py-5 text-sm bg-white border-b border-gray-200">
|
||||
<p className="text-gray-900 whitespace-no-wrap">
|
||||
{ measure.time.toString() }
|
||||
</p>
|
||||
</td>
|
||||
<td className="px-5 py-5 text-sm bg-white border-b border-gray-200">
|
||||
<p className="text-gray-900 whitespace-no-wrap">
|
||||
<span
|
||||
className="relative inline-block px-3 py-1 font-semibold leading-tight bg-gray-200 rounded-lg">
|
||||
{ measure.sensor_uuid }
|
||||
</span>
|
||||
</p>
|
||||
</td>
|
||||
<td className="px-5 py-5 text-sm bg-white border-b border-gray-200">
|
||||
<p className="text-gray-900 whitespace-no-wrap">
|
||||
{ measure.createdAt.toString() }
|
||||
</p>
|
||||
</td>
|
||||
<td className="px-5 py-5 text-sm bg-white border-b border-gray-200">
|
||||
<span
|
||||
className="relative inline-block px-3 py-1 font-semibold leading-tight text-green-900">
|
||||
<span aria-hidden="true"
|
||||
className="absolute inset-0 bg-green-200 rounded-full opacity-50">
|
||||
</span>
|
||||
<span className="relative">
|
||||
deactive
|
||||
</span>
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
)
|
||||
)
|
||||
}
|
||||
</tbody>
|
||||
</table>
|
||||
{
|
||||
measures?.length === 0 && <div className={'flex items-center justify-center justify-items-center space-x-2 py-2 w-full'}>
|
||||
<img src={OK} className={'h-6 w-6'} alt=""/>
|
||||
<p>Notion not found. All sensors working correct!</p>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
|
||||
<div className="w-1/4">
|
||||
<Pie data={data} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default PotantialProblemeSensorsTable;
|
@ -0,0 +1,7 @@
|
||||
/*
|
||||
* Replace this with your own classes
|
||||
*
|
||||
* e.g.
|
||||
* .container {
|
||||
* }
|
||||
*/
|
@ -0,0 +1,10 @@
|
||||
import { render } from '@testing-library/react';
|
||||
|
||||
import SensorsLuminGraph from './sensors-lumin-graph';
|
||||
|
||||
describe('SensorsLuminGraph', () => {
|
||||
it('should render successfully', () => {
|
||||
const { baseElement } = render(<SensorsLuminGraph />);
|
||||
expect(baseElement).toBeTruthy();
|
||||
});
|
||||
});
|
@ -0,0 +1,74 @@
|
||||
import styles from './sensors-lumin-graph.module.scss';
|
||||
import {
|
||||
CategoryScale,
|
||||
Chart as ChartJS,
|
||||
Legend,
|
||||
LinearScale,
|
||||
LineElement,
|
||||
PointElement,
|
||||
Title,
|
||||
Tooltip
|
||||
} from "chart.js";
|
||||
import {Line} from "react-chartjs-2";
|
||||
|
||||
ChartJS.register(
|
||||
CategoryScale,
|
||||
LinearScale,
|
||||
PointElement,
|
||||
LineElement,
|
||||
Title,
|
||||
Tooltip,
|
||||
Legend,
|
||||
);
|
||||
|
||||
const options = {
|
||||
responsive: true,
|
||||
plugins: {
|
||||
legend: {
|
||||
position: "top" as const,
|
||||
},
|
||||
title: {
|
||||
display: true,
|
||||
text: "Sensors Bright Graph",
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
interface DataPoint {
|
||||
time: string;
|
||||
value: string;
|
||||
}
|
||||
|
||||
|
||||
/* eslint-disable-next-line */
|
||||
export interface SensorsLuminGraphProps {
|
||||
data: DataPoint[];
|
||||
}
|
||||
|
||||
export function SensorsLuminGraph(props: SensorsLuminGraphProps) {
|
||||
const labels = props.data.map(item => parseInt(item.time));
|
||||
const Lumen = props.data.map(item => parseInt(item.value));
|
||||
Lumen.reverse();
|
||||
|
||||
const data = {
|
||||
labels,
|
||||
datasets: [
|
||||
{
|
||||
label: "Bright",
|
||||
data: Lumen,
|
||||
borderColor: 'rgb(255, 165, 0)',
|
||||
backgroundColor: 'rgba(255, 165, 0, 0.5)',
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
return (
|
||||
<div className={'w-1/3 '}>
|
||||
<div className={'p-4 bg-white shadow-lg rounded-xl ring-1 ring-gray-100'}>
|
||||
<Line options={options} data={data} />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default SensorsLuminGraph;
|
@ -0,0 +1,7 @@
|
||||
/*
|
||||
* Replace this with your own classes
|
||||
*
|
||||
* e.g.
|
||||
* .container {
|
||||
* }
|
||||
*/
|
@ -0,0 +1,10 @@
|
||||
import { render } from '@testing-library/react';
|
||||
|
||||
import SensorsVebrationsGraph from './sensors-vebrations-graph';
|
||||
|
||||
describe('SensorsVebrationsGraph', () => {
|
||||
it('should render successfully', () => {
|
||||
const { baseElement } = render(<SensorsVebrationsGraph />);
|
||||
expect(baseElement).toBeTruthy();
|
||||
});
|
||||
});
|
@ -0,0 +1,73 @@
|
||||
import styles from './sensors-vebrations-graph.module.scss';
|
||||
import {Line} from "react-chartjs-2";
|
||||
import {
|
||||
Chart as ChartJS,
|
||||
CategoryScale,
|
||||
LinearScale,
|
||||
PointElement,
|
||||
LineElement,
|
||||
Title,
|
||||
Tooltip,
|
||||
Legend,
|
||||
} from "chart.js";
|
||||
|
||||
ChartJS.register(
|
||||
CategoryScale,
|
||||
LinearScale,
|
||||
PointElement,
|
||||
LineElement,
|
||||
Title,
|
||||
Tooltip,
|
||||
Legend,
|
||||
);
|
||||
|
||||
export const options = {
|
||||
responsive: true,
|
||||
plugins: {
|
||||
legend: {
|
||||
position: "top" as const,
|
||||
},
|
||||
title: {
|
||||
display: true,
|
||||
text: "Sensors Vibration Graph",
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
interface DataPoint {
|
||||
time: string;
|
||||
value: string;
|
||||
}
|
||||
|
||||
/* eslint-disable-next-line */
|
||||
export interface SensorsVebrationsGraphProps {
|
||||
data: DataPoint[];
|
||||
}
|
||||
|
||||
export function SensorsVebrationsGraph(props: SensorsVebrationsGraphProps) {
|
||||
const labels = props.data.map(item => parseInt(item.time));
|
||||
const vibrations = props.data.map(item => parseInt(item.value));
|
||||
vibrations.reverse();
|
||||
|
||||
const data = {
|
||||
labels,
|
||||
datasets: [
|
||||
{
|
||||
label: "Vibration",
|
||||
data: vibrations,
|
||||
borderColor: "rgb(255, 99, 132)",
|
||||
backgroundColor: "rgba(255, 99, 132, 0.5)",
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
return (
|
||||
<div className={'w-full h-full '}>
|
||||
<div className={'p-4 bg-white shadow-lg rounded-xl ring-1 ring-gray-100'}>
|
||||
<Line options={options} data={data} />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default SensorsVebrationsGraph;
|
@ -1,2 +1,3 @@
|
||||
export * from './lib/sensors-on-map/sensors-on-map';
|
||||
export * from './lib/nav-link/nav-link';
|
||||
export * from './lib/ui';
|
||||
|
@ -0,0 +1,7 @@
|
||||
/*
|
||||
* Replace this with your own classes
|
||||
*
|
||||
* e.g.
|
||||
* .container {
|
||||
* }
|
||||
*/
|
@ -0,0 +1,10 @@
|
||||
import { render } from '@testing-library/react';
|
||||
|
||||
import SensorsOnMap from './sensors-on-map';
|
||||
|
||||
describe('SensorsOnMap', () => {
|
||||
it('should render successfully', () => {
|
||||
const { baseElement } = render(<SensorsOnMap />);
|
||||
expect(baseElement).toBeTruthy();
|
||||
});
|
||||
});
|
@ -0,0 +1,112 @@
|
||||
import styles from './sensors-on-map.module.scss';
|
||||
import {YMaps, Map, Circle, Clusterer, Placemark} from '@pbe/react-yandex-maps';
|
||||
import {Prisma, Sensor} from "@weather-platform/prisma-clients/Sensors";
|
||||
import {Prisma as PrismaAgr, Agregator} from "@weather-platform/prisma-clients/Agregators";
|
||||
import axios from "axios";
|
||||
import {AGW_URL} from "../../../../agw";
|
||||
import {useEffect, useState} from "react";
|
||||
|
||||
/* eslint-disable-next-line */
|
||||
export interface SensorsOnMapProps {}
|
||||
|
||||
export function SensorsOnMap(props: SensorsOnMapProps) {
|
||||
const fetchGetSensorsList = async (params: Prisma.SensorFindManyArgs = {}) => {
|
||||
try {
|
||||
const response = await axios.post( AGW_URL + '/api/v1/sensors/get-with-params', params);
|
||||
const data = response.data;
|
||||
return data;
|
||||
} catch (error) {
|
||||
console.error('Error fetching data:', error);
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
const [sensors, setSensors] = useState<Sensor[] | null>(null);
|
||||
|
||||
const updateSensorsData = async () => {
|
||||
const response = await fetchGetSensorsList({
|
||||
select: {
|
||||
lat: true,
|
||||
lng: true,
|
||||
}
|
||||
});
|
||||
if (response !== null) {
|
||||
setSensors(response);
|
||||
}
|
||||
};
|
||||
|
||||
const fetchGetAgregatorsList = async (params: PrismaAgr.AgregatorFindManyArgs = {}) => {
|
||||
try {
|
||||
const response = await axios.post( AGW_URL + '/api/v1/agregator/get-with-params', params);
|
||||
const data = response.data;
|
||||
return data;
|
||||
} catch (error) {
|
||||
console.error('Error fetching data:', error);
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
const [agregators, setAgregators] = useState<Agregator[] | null>(null);
|
||||
|
||||
const updateAgregatorsData = async () => {
|
||||
const response = await fetchGetAgregatorsList({
|
||||
select: {
|
||||
lat: true,
|
||||
lng: true,
|
||||
}
|
||||
});
|
||||
if (response !== null) {
|
||||
setAgregators(response);
|
||||
}
|
||||
};
|
||||
|
||||
function upd() {
|
||||
updateAgregatorsData();
|
||||
updateSensorsData();
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
upd();
|
||||
const interval = setInterval(upd, 30000);
|
||||
return () => clearInterval(interval);
|
||||
}, []);
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore
|
||||
// const mergedArray = [...agregators, ...sensors];
|
||||
// const temperatures = agregators.map(item => [item.lng, item.lat]);
|
||||
// console.log(temperatures);
|
||||
return (
|
||||
<div className="rounded-2xl w-full h-full mx-4">
|
||||
<YMaps>
|
||||
<Map defaultState={{ center: [47.2362, 38.8969], zoom: 11 }} width={"100%"} height={"100%"}>
|
||||
<Circle
|
||||
geometry={[[47.205577, 38.941490], 5000]}
|
||||
options={{
|
||||
draggable: false,
|
||||
fillColor: "#DB709377",
|
||||
strokeColor: "#990066",
|
||||
strokeOpacity: 0.8,
|
||||
strokeWidth: 5,
|
||||
}}
|
||||
/>
|
||||
<Clusterer
|
||||
options={{
|
||||
preset: "islands#invertedVioletClusterIcons",
|
||||
groupByCoordinates: false,
|
||||
}}
|
||||
>
|
||||
{agregators?.map((agregator:any, index:any) => (
|
||||
<Placemark key={index} geometry={{ type: "Point", coordinates: [agregator.lat, agregator.lng] }} />
|
||||
))}
|
||||
{sensors?.map((agregator:any, index:any) => (
|
||||
<Placemark key={index} geometry={{ type: "Point", coordinates: [agregator.lat, agregator.lng] }} />
|
||||
))}
|
||||
</Clusterer>
|
||||
</Map>
|
||||
</YMaps>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default SensorsOnMap;
|
Loading…
Reference in new issue