Fix jwt-token
This commit is contained in:
@@ -1334,7 +1334,7 @@ const AlertDetailsModal = ({ alert, parseErrorMessage, onClose }) => {
|
|||||||
<div className="text-gray-600 break-all">{alert.recipient}</div>
|
<div className="text-gray-600 break-all">{alert.recipient}</div>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<span className="font-medium text-gray-700">Retry Count:</span>
|
<span className="font-medium text-gray-700">{t('alerts.retryCount')}:</span>
|
||||||
<div className="text-gray-600">{alert.retry_count}</div>
|
<div className="text-gray-600">{alert.retry_count}</div>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import React, { useState, useEffect } from 'react';
|
|||||||
import api from '../services/api';
|
import api from '../services/api';
|
||||||
import { format } from 'date-fns';
|
import { format } from 'date-fns';
|
||||||
import { formatFrequency } from '../utils/formatFrequency';
|
import { formatFrequency } from '../utils/formatFrequency';
|
||||||
import { t } from '../utils/tempTranslations'; // Temporary translation system
|
import { useTranslation } from '../utils/tempTranslations';
|
||||||
import {
|
import {
|
||||||
MagnifyingGlassIcon,
|
MagnifyingGlassIcon,
|
||||||
FunnelIcon,
|
FunnelIcon,
|
||||||
@@ -10,6 +10,7 @@ import {
|
|||||||
} from '@heroicons/react/24/outline';
|
} from '@heroicons/react/24/outline';
|
||||||
|
|
||||||
const Detections = () => {
|
const Detections = () => {
|
||||||
|
const { t } = useTranslation();
|
||||||
const [detections, setDetections] = useState([]);
|
const [detections, setDetections] = useState([]);
|
||||||
const [loading, setLoading] = useState(true);
|
const [loading, setLoading] = useState(true);
|
||||||
const [pagination, setPagination] = useState({});
|
const [pagination, setPagination] = useState({});
|
||||||
@@ -85,7 +86,7 @@ const Detections = () => {
|
|||||||
{t('detections.title')}
|
{t('detections.title')}
|
||||||
</h3>
|
</h3>
|
||||||
<p className="mt-1 text-sm text-gray-500">
|
<p className="mt-1 text-sm text-gray-500">
|
||||||
History of all drone detections from your devices
|
{t('detections.description')}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<button
|
<button
|
||||||
@@ -93,7 +94,7 @@ const Detections = () => {
|
|||||||
className="btn btn-secondary flex items-center space-x-2"
|
className="btn btn-secondary flex items-center space-x-2"
|
||||||
>
|
>
|
||||||
<FunnelIcon className="h-4 w-4" />
|
<FunnelIcon className="h-4 w-4" />
|
||||||
<span>Filters</span>
|
<span>{t('detections.filters')}</span>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -103,12 +104,12 @@ const Detections = () => {
|
|||||||
<div className="grid grid-cols-1 md:grid-cols-4 gap-4">
|
<div className="grid grid-cols-1 md:grid-cols-4 gap-4">
|
||||||
<div>
|
<div>
|
||||||
<label className="block text-sm font-medium text-gray-700 mb-1">
|
<label className="block text-sm font-medium text-gray-700 mb-1">
|
||||||
Device ID
|
{t('detections.deviceId')}
|
||||||
</label>
|
</label>
|
||||||
<input
|
<input
|
||||||
type="number"
|
type="text"
|
||||||
className="w-full border border-gray-300 rounded-md px-3 py-2 focus:ring-primary-500 focus:border-primary-500"
|
className="w-full border border-gray-300 rounded-md px-3 py-2 focus:ring-primary-500 focus:border-primary-500"
|
||||||
placeholder="Device ID"
|
placeholder={t('detections.deviceIdPlaceholder')}
|
||||||
value={filters.device_id}
|
value={filters.device_id}
|
||||||
onChange={(e) => handleFilterChange('device_id', e.target.value)}
|
onChange={(e) => handleFilterChange('device_id', e.target.value)}
|
||||||
/>
|
/>
|
||||||
@@ -116,12 +117,12 @@ const Detections = () => {
|
|||||||
|
|
||||||
<div>
|
<div>
|
||||||
<label className="block text-sm font-medium text-gray-700 mb-1">
|
<label className="block text-sm font-medium text-gray-700 mb-1">
|
||||||
Drone ID
|
{t('detections.droneId')}
|
||||||
</label>
|
</label>
|
||||||
<input
|
<input
|
||||||
type="number"
|
type="text"
|
||||||
className="w-full border border-gray-300 rounded-md px-3 py-2 focus:ring-primary-500 focus:border-primary-500"
|
className="w-full border border-gray-300 rounded-md px-3 py-2 focus:ring-primary-500 focus:border-primary-500"
|
||||||
placeholder="Drone ID"
|
placeholder={t('detections.droneIdPlaceholder')}
|
||||||
value={filters.drone_id}
|
value={filters.drone_id}
|
||||||
onChange={(e) => handleFilterChange('drone_id', e.target.value)}
|
onChange={(e) => handleFilterChange('drone_id', e.target.value)}
|
||||||
/>
|
/>
|
||||||
@@ -129,7 +130,7 @@ const Detections = () => {
|
|||||||
|
|
||||||
<div>
|
<div>
|
||||||
<label className="block text-sm font-medium text-gray-700 mb-1">
|
<label className="block text-sm font-medium text-gray-700 mb-1">
|
||||||
Start Date
|
{t('detections.startDate')}
|
||||||
</label>
|
</label>
|
||||||
<input
|
<input
|
||||||
type="datetime-local"
|
type="datetime-local"
|
||||||
@@ -141,7 +142,7 @@ const Detections = () => {
|
|||||||
|
|
||||||
<div>
|
<div>
|
||||||
<label className="block text-sm font-medium text-gray-700 mb-1">
|
<label className="block text-sm font-medium text-gray-700 mb-1">
|
||||||
End Date
|
{t('detections.endDate')}
|
||||||
</label>
|
</label>
|
||||||
<input
|
<input
|
||||||
type="datetime-local"
|
type="datetime-local"
|
||||||
@@ -157,7 +158,7 @@ const Detections = () => {
|
|||||||
onClick={clearFilters}
|
onClick={clearFilters}
|
||||||
className="btn btn-secondary"
|
className="btn btn-secondary"
|
||||||
>
|
>
|
||||||
Clear Filters
|
{t('detections.clearFilters')}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -175,14 +176,14 @@ const Detections = () => {
|
|||||||
<table className="table">
|
<table className="table">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>Device</th>
|
<th>{t('detections.device')}</th>
|
||||||
<th>Drone ID</th>
|
<th>{t('detections.droneId')}</th>
|
||||||
<th>Type</th>
|
<th>{t('detections.type')}</th>
|
||||||
<th>Frequency</th>
|
<th>{t('detections.frequency')}</th>
|
||||||
<th>RSSI</th>
|
<th>{t('detections.rssi')}</th>
|
||||||
<th>Location</th>
|
<th>{t('detections.location')}</th>
|
||||||
<th>Detected At</th>
|
<th>{t('detections.detectedAt')}</th>
|
||||||
<th>Actions</th>
|
<th>{t('detections.actions')}</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
@@ -231,7 +232,7 @@ const Detections = () => {
|
|||||||
{detection.device?.location_description ||
|
{detection.device?.location_description ||
|
||||||
(detection.geo_lat && detection.geo_lon ?
|
(detection.geo_lat && detection.geo_lon ?
|
||||||
`${detection.geo_lat}, ${detection.geo_lon}` :
|
`${detection.geo_lat}, ${detection.geo_lon}` :
|
||||||
'Unknown')}
|
t('detections.unknown'))}
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
@@ -264,7 +265,7 @@ const Detections = () => {
|
|||||||
<MagnifyingGlassIcon className="mx-auto h-12 w-12 text-gray-400" />
|
<MagnifyingGlassIcon className="mx-auto h-12 w-12 text-gray-400" />
|
||||||
<h3 className="mt-2 text-sm font-medium text-gray-900">{t('detections.noDetections')}</h3>
|
<h3 className="mt-2 text-sm font-medium text-gray-900">{t('detections.noDetections')}</h3>
|
||||||
<p className="mt-1 text-sm text-gray-500">
|
<p className="mt-1 text-sm text-gray-500">
|
||||||
Try adjusting your search filters.
|
{t('detections.tryAdjustingFilters')}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
@@ -278,29 +279,29 @@ const Detections = () => {
|
|||||||
disabled={filters.offset === 0}
|
disabled={filters.offset === 0}
|
||||||
className="relative inline-flex items-center px-4 py-2 border border-gray-300 text-sm font-medium rounded-md text-gray-700 bg-white hover:bg-gray-50 disabled:opacity-50"
|
className="relative inline-flex items-center px-4 py-2 border border-gray-300 text-sm font-medium rounded-md text-gray-700 bg-white hover:bg-gray-50 disabled:opacity-50"
|
||||||
>
|
>
|
||||||
Previous
|
{t('detections.previous')}
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
onClick={() => handlePageChange(filters.offset + filters.limit)}
|
onClick={() => handlePageChange(filters.offset + filters.limit)}
|
||||||
disabled={filters.offset + filters.limit >= pagination.total}
|
disabled={filters.offset + filters.limit >= pagination.total}
|
||||||
className="ml-3 relative inline-flex items-center px-4 py-2 border border-gray-300 text-sm font-medium rounded-md text-gray-700 bg-white hover:bg-gray-50 disabled:opacity-50"
|
className="ml-3 relative inline-flex items-center px-4 py-2 border border-gray-300 text-sm font-medium rounded-md text-gray-700 bg-white hover:bg-gray-50 disabled:opacity-50"
|
||||||
>
|
>
|
||||||
Next
|
{t('detections.next')}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="hidden sm:flex-1 sm:flex sm:items-center sm:justify-between">
|
<div className="hidden sm:flex-1 sm:flex sm:items-center sm:justify-between">
|
||||||
<div>
|
<div>
|
||||||
<p className="text-sm text-gray-700">
|
<p className="text-sm text-gray-700">
|
||||||
Showing{' '}
|
{t('detections.showing')} {' '}
|
||||||
<span className="font-medium">{filters.offset + 1}</span>
|
<span className="font-medium">{filters.offset + 1}</span>
|
||||||
{' '}to{' '}
|
{' '}{t('detections.to')}{' '}
|
||||||
<span className="font-medium">
|
<span className="font-medium">
|
||||||
{Math.min(filters.offset + filters.limit, pagination.total)}
|
{Math.min(filters.offset + filters.limit, pagination.total)}
|
||||||
</span>
|
</span>
|
||||||
{' '}of{' '}
|
{' '}{t('detections.of')}{' '}
|
||||||
<span className="font-medium">{pagination.total}</span>
|
<span className="font-medium">{pagination.total}</span>
|
||||||
{' '}results
|
{' '}{t('detections.results')}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -311,14 +312,14 @@ const Detections = () => {
|
|||||||
disabled={filters.offset === 0}
|
disabled={filters.offset === 0}
|
||||||
className="relative inline-flex items-center px-2 py-2 rounded-l-md border border-gray-300 bg-white text-sm font-medium text-gray-500 hover:bg-gray-50 disabled:opacity-50"
|
className="relative inline-flex items-center px-2 py-2 rounded-l-md border border-gray-300 bg-white text-sm font-medium text-gray-500 hover:bg-gray-50 disabled:opacity-50"
|
||||||
>
|
>
|
||||||
Previous
|
{t('detections.previous')}
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
onClick={() => handlePageChange(filters.offset + filters.limit)}
|
onClick={() => handlePageChange(filters.offset + filters.limit)}
|
||||||
disabled={filters.offset + filters.limit >= pagination.total}
|
disabled={filters.offset + filters.limit >= pagination.total}
|
||||||
className="relative inline-flex items-center px-2 py-2 rounded-r-md border border-gray-300 bg-white text-sm font-medium text-gray-500 hover:bg-gray-50 disabled:opacity-50"
|
className="relative inline-flex items-center px-2 py-2 rounded-r-md border border-gray-300 bg-white text-sm font-medium text-gray-500 hover:bg-gray-50 disabled:opacity-50"
|
||||||
>
|
>
|
||||||
Next
|
{t('detections.next')}
|
||||||
</button>
|
</button>
|
||||||
</nav>
|
</nav>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -89,7 +89,26 @@ const translations = {
|
|||||||
showOnMap: 'Show on Map',
|
showOnMap: 'Show on Map',
|
||||||
highConfidence: 'High Confidence',
|
highConfidence: 'High Confidence',
|
||||||
mediumConfidence: 'Medium Confidence',
|
mediumConfidence: 'Medium Confidence',
|
||||||
lowConfidence: 'Low Confidence'
|
lowConfidence: 'Low Confidence',
|
||||||
|
filters: 'Filters',
|
||||||
|
deviceId: 'Device ID',
|
||||||
|
droneId: 'Drone ID',
|
||||||
|
startDate: 'Start Date',
|
||||||
|
endDate: 'End Date',
|
||||||
|
clearFilters: 'Clear Filters',
|
||||||
|
deviceIdPlaceholder: 'Enter device ID',
|
||||||
|
droneIdPlaceholder: 'Enter drone ID',
|
||||||
|
frequency: 'Frequency',
|
||||||
|
rssi: 'RSSI',
|
||||||
|
detectedAt: 'Detected At',
|
||||||
|
unknown: 'Unknown',
|
||||||
|
tryAdjustingFilters: 'Try adjusting your search filters.',
|
||||||
|
previous: 'Previous',
|
||||||
|
next: 'Next',
|
||||||
|
showing: 'Showing',
|
||||||
|
to: 'to',
|
||||||
|
of: 'of',
|
||||||
|
results: 'results'
|
||||||
},
|
},
|
||||||
devices: {
|
devices: {
|
||||||
title: 'All Devices',
|
title: 'All Devices',
|
||||||
@@ -323,7 +342,7 @@ const translations = {
|
|||||||
multipleContacts: 'Multiple Contacts',
|
multipleContacts: 'Multiple Contacts',
|
||||||
noDevicesFound: 'No devices found',
|
noDevicesFound: 'No devices found',
|
||||||
mapLegend: 'Map Legend',
|
mapLegend: 'Map Legend',
|
||||||
deviceDetecting: 'Device Detecting',
|
deviceDetecting: 'Active Detection',
|
||||||
droneDetectionRings: 'Drone Detection Rings',
|
droneDetectionRings: 'Drone Detection Rings',
|
||||||
ringsDescription: 'Rings show estimated detection range based on RSSI',
|
ringsDescription: 'Rings show estimated detection range based on RSSI',
|
||||||
orlanMilitary: 'Military-drone (Always Critical)',
|
orlanMilitary: 'Military-drone (Always Critical)',
|
||||||
@@ -512,6 +531,7 @@ const translations = {
|
|||||||
channel: 'Channel',
|
channel: 'Channel',
|
||||||
channels: 'Channels',
|
channels: 'Channels',
|
||||||
status: 'Status',
|
status: 'Status',
|
||||||
|
retryCount: 'Retry Count',
|
||||||
message: 'Message',
|
message: 'Message',
|
||||||
detectionDetails: 'Detection Details',
|
detectionDetails: 'Detection Details',
|
||||||
viewDetails: 'View Details',
|
viewDetails: 'View Details',
|
||||||
@@ -769,7 +789,26 @@ const translations = {
|
|||||||
showOnMap: 'Visa på karta',
|
showOnMap: 'Visa på karta',
|
||||||
highConfidence: 'Hög säkerhet',
|
highConfidence: 'Hög säkerhet',
|
||||||
mediumConfidence: 'Medel säkerhet',
|
mediumConfidence: 'Medel säkerhet',
|
||||||
lowConfidence: 'Låg säkerhet'
|
lowConfidence: 'Låg säkerhet',
|
||||||
|
filters: 'Filter',
|
||||||
|
deviceId: 'Enhets-ID',
|
||||||
|
droneId: 'Drönare-ID',
|
||||||
|
startDate: 'Startdatum',
|
||||||
|
endDate: 'Slutdatum',
|
||||||
|
clearFilters: 'Rensa filter',
|
||||||
|
deviceIdPlaceholder: 'Ange enhets-ID',
|
||||||
|
droneIdPlaceholder: 'Ange drönare-ID',
|
||||||
|
frequency: 'Frekvens',
|
||||||
|
rssi: 'RSSI',
|
||||||
|
detectedAt: 'Detekterad vid',
|
||||||
|
unknown: 'Okänd',
|
||||||
|
tryAdjustingFilters: 'Försök justera dina sökfilter.',
|
||||||
|
previous: 'Föregående',
|
||||||
|
next: 'Nästa',
|
||||||
|
showing: 'Visar',
|
||||||
|
to: 'till',
|
||||||
|
of: 'av',
|
||||||
|
results: 'resultat'
|
||||||
},
|
},
|
||||||
devices: {
|
devices: {
|
||||||
title: 'Alla enheter',
|
title: 'Alla enheter',
|
||||||
@@ -1003,7 +1042,7 @@ const translations = {
|
|||||||
multipleContacts: 'Flera kontakter',
|
multipleContacts: 'Flera kontakter',
|
||||||
noDevicesFound: 'Inga enheter hittades',
|
noDevicesFound: 'Inga enheter hittades',
|
||||||
mapLegend: 'Kartteckenförklaring',
|
mapLegend: 'Kartteckenförklaring',
|
||||||
deviceDetecting: 'Enhet detekterar',
|
deviceDetecting: 'Aktiv detektion',
|
||||||
droneDetectionRings: 'Drönardetekteringsringar',
|
droneDetectionRings: 'Drönardetekteringsringar',
|
||||||
ringsDescription: 'Ringar visar uppskattad detekteringsräckvidd baserat på RSSI',
|
ringsDescription: 'Ringar visar uppskattad detekteringsräckvidd baserat på RSSI',
|
||||||
orlanMilitary: 'Militärdrönare (Alltid kritisk)',
|
orlanMilitary: 'Militärdrönare (Alltid kritisk)',
|
||||||
@@ -1192,6 +1231,7 @@ const translations = {
|
|||||||
channel: 'Kanal',
|
channel: 'Kanal',
|
||||||
channels: 'Kanaler',
|
channels: 'Kanaler',
|
||||||
status: 'Status',
|
status: 'Status',
|
||||||
|
retryCount: 'Antal återförsök',
|
||||||
message: 'Meddelande',
|
message: 'Meddelande',
|
||||||
detectionDetails: 'Detekteringsdetaljer',
|
detectionDetails: 'Detekteringsdetaljer',
|
||||||
viewDetails: 'Visa detaljer',
|
viewDetails: 'Visa detaljer',
|
||||||
|
|||||||
Reference in New Issue
Block a user