import React, { useEffect, useLayoutEffect, useState, useRef, useCallback, useMemo } from "react"; import { Link, useLocation, useParams, useNavigate } from 'react-router-dom'; import ListTalkgroups from "../Talkgroups/ListTalkgroups.js"; import MessageBox from "../Components/Message.js"; import ListGroups from "../Group/ListGroups.js"; import GroupModal from "../Group/GroupModal.js"; import ErrorChart from "./ResponsiveErrorChart" import CallChart from "./ResponsiveCallChart" import { useGetSystemsQuery, useGetTalkgroupsQuery, useGetGroupsQuery, useGetErrorsQuery, useDeleteGroupMutation, useDeleteSystemMutation, useImportTalkgroupsMutation, useSaveGroupOrderMutation } from '../features/api/apiSlice' import { Button, Confirm, Icon, Form, TextArea, Header, Container, Message, List, Segment, Tab, Divider, Label } from "semantic-ui-react"; const System = (props) => { const { shortName } = useParams(); const navigate = useNavigate(); const { data: systemsData, isSuccess: isSystemsSuccess } = useGetSystemsQuery(); const { data: talkgroupsData, isSuccess: isTalkgroupsSuccess } = useGetTalkgroupsQuery(shortName); const { data: groupsData, isSuccess: isGroupsSuccess } = useGetGroupsQuery(shortName); const { data: errorsData, isSuccess: isErrorsSuccess } = useGetErrorsQuery(shortName); const [deleteGroupAPI, { isLoading: isDeleting }] = useDeleteGroupMutation(); const [reorderGroupsAPI, { isLoading: isReordering }] = useSaveGroupOrderMutation(); const [importTalkgroupsAPI, { isLoading: isImporting }] = useImportTalkgroupsMutation(); const [deleteSystemAPI ] = useDeleteSystemMutation(); const [openSystemDeleteConfirm, setOpenSystemDeleteConfirm] = useState(false); const [openPermissionDeleteConfirm, setOpenPermissionDeleteConfirm] = useState(false); const [openMessage, setOpenMessage] = useState(false); const [requestMessage, setRequestMessage] = useState(""); const [groupVisible, setGroupVisible] = useState(false); const [editGroupId, setEditGroupId] = useState(false); const [errorData, setErrorData] = useState({}); const [callData, setCallData] = useState({}); const [groupOrder, setGroupOrder] = useState([]); const processErrors = (errors) => { var allData = []; var num = 0; const now = new Date(); var maxDate = now; var minDate = now; var minValue = 0; var maxValue = 0; var legend = []; for (var j = 0; j < errors.length; j++) { var data = []; for (var i = 0; i < errors[j].values.length; i++) { var time = new Date(errors[j].values[i].time); if (errors[j].values[i].errors > maxValue) maxValue = errors[j].values[i].errors; if (time < minDate) minDate = time; var value = { id: num++, y: errors[j].values[i].errors, x: time }; data.push(value); } const id = Math.floor(errors[j]._id / 1000) / 1000 + "MHz"; legend.push(id); var obj = { id: id, data: data }; allData.push(obj); } const errorData = { data: allData, minDate: minDate, maxDate: maxDate, minValue: minValue, maxValue: maxValue, legend: legend }; setErrorData(errorData); }; const processStatistics = (statistic) => { var callTotals = []; var errorTotals = []; const now = new Date(); var maxDate = now; var minDate = now; var minValue = 0; var maxValue = 0; var MS_PER_MINUTE = 60000; if (statistic) { for (var j = 0; j < statistic.callTotals.length; j++) { var spotsBack = statistic.callTotals.length - j; var time = new Date(now - spotsBack * 15 * MS_PER_MINUTE); if (time < minDate) minDate = time; if (statistic.callTotals[j] > maxValue) maxValue = statistic.callTotals[j]; callTotals.push({ y: statistic.callTotals[j], x: time }); } for (var j = 0; j < statistic.errorTotals.length; j++) { var spotsBack = statistic.errorTotals.length - j; var time = new Date(now - spotsBack * 15 * MS_PER_MINUTE); if (time < minDate) minDate = time; if (statistic.errorTotals[j] > maxValue) maxValue = statistic.errorTotals[j]; errorTotals.push({ x: time, y: statistic.errorTotals[j] }); } const callData = { minDate: minDate, maxDate: maxDate, minValue: minValue, maxValue: maxValue, callTotals: callTotals, errorTotals: errorTotals }; setCallData(callData); } } /* componentDidMount() { this.props.systemActions.fetchSystems(); this.props.talkgroupActions.fetchTalkgroups(this.props.shortName); this.props.groupActions.fetchGroups(this.props.shortName); this.props.errorActions.fetch(this.props.shortName); if (this.props.statistic) { this.processStatistics(this.props.statistic); } if (this.props.errors) { this.processErrors(this.props.errors); } } componentDidUpdate(prevProp) { // If we just received the error statistics for a system, for the first time, proccess them. if (this.props.errors && !prevProp.errors) { this.processErrors(this.props.errors); } // If we just received the call statistics for a system, for the first time, proccess them. if (this.props.statistic && !prevProp.statistic) { this.processStatistics(this.props.statistic); } } */ const editGroup = (groupId) => { setEditGroupId(groupId) setGroupVisible((state) => !state) } const deleteGroup = async (groupId) => { for (const num in groupsData) { if (groupsData[num]._id == groupId) { await deleteGroupAPI(groupsData[num]) } } } const reorderGroup = (oldIndex, newIndex) => { if ((newIndex < 0) || (newIndex > (groupOrder.length - 1))) { return } const moveOrder = groupOrder.slice(); moveOrder.splice(newIndex, 0, moveOrder.splice(oldIndex, 1)[0]); setGroupOrder(moveOrder); } const handleGroupClose = () => { setEditGroupId(false) setGroupVisible(false) } const handleGroupToggle = () => { setEditGroupId(false) setGroupVisible((state) => !state) } const saveGroupOrder = async () => { await reorderGroupsAPI({ shortName: shortName, order: { groupOrder: JSON.stringify(groupOrder) } }); } const handleUpload = async (file) => { const formData = new FormData(); formData.append('file', file) await importTalkgroupsAPI({ shortName: shortName, file: formData }); } const handleSystemDeleteConfirm = async () => { setOpenSystemDeleteConfirm(false); try { const originalPromiseResult = await deleteSystemAPI(shortName).unwrap(); navigate("/list-systems") } catch (error) { const message = error.data.message; console.log(message); setRequestMessage(message); } }; const handleSystemDeleteCancel = () => setOpenSystemDeleteConfirm(false); let system = false; if (isSystemsSuccess) { system = systemsData.systems.find(sys => sys.shortName == shortName); } useLayoutEffect(() => { if (groupsData) { let newOrder = []; groupsData.forEach(group => { newOrder.push(group._id); }); setGroupOrder(newOrder); } }, [groupsData]) useEffect(() => { if (isSystemsSuccess) { processStatistics(systemsData.stats[shortName]) } }, [isSystemsSuccess]); useEffect(() => { if (isErrorsSuccess) { processErrors(errorData) } }, [isErrorsSuccess]); let fileInput = null; var location = ""; var example = ""; var groupRender = () => { }; if (system) { if (isTalkgroupsSuccess && talkgroupsData.length) { groupRender = () => (
Below are the parameters you will need to configure Trunk Recorder. The example below shows how they should be added to the config.json file.
This is the same .csv talkgroup file from Trunk Recorder... except the Hex column has been deleted
The columns for the file are: