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/nav-link/nav-link';
|
||||||
export * from './lib/ui';
|
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