Fix jwt-token
This commit is contained in:
@@ -462,10 +462,32 @@ const CreateAlertRuleModal = ({ onClose, onSave }) => {
|
|||||||
device_ids: [],
|
device_ids: [],
|
||||||
drone_types: [],
|
drone_types: [],
|
||||||
min_rssi: '',
|
min_rssi: '',
|
||||||
max_rssi: '',
|
max_rssi: ''
|
||||||
frequency_ranges: []
|
|
||||||
});
|
});
|
||||||
const [saving, setSaving] = useState(false);
|
const [saving, setSaving] = useState(false);
|
||||||
|
const [devices, setDevices] = useState([]);
|
||||||
|
const [droneTypes, setDroneTypes] = useState([]);
|
||||||
|
const [loadingData, setLoadingData] = useState(true);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
fetchDevicesAndDroneTypes();
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const fetchDevicesAndDroneTypes = async () => {
|
||||||
|
try {
|
||||||
|
const [devicesResponse, droneTypesResponse] = await Promise.all([
|
||||||
|
api.get('/devices'),
|
||||||
|
api.get('/drone-types')
|
||||||
|
]);
|
||||||
|
|
||||||
|
setDevices(devicesResponse.data.data || []);
|
||||||
|
setDroneTypes(droneTypesResponse.data.data || []);
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error fetching devices and drone types:', error);
|
||||||
|
} finally {
|
||||||
|
setLoadingData(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const handleSubmit = async (e) => {
|
const handleSubmit = async (e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
@@ -479,7 +501,6 @@ const CreateAlertRuleModal = ({ onClose, onSave }) => {
|
|||||||
if (!payload.max_rssi) delete payload.max_rssi;
|
if (!payload.max_rssi) delete payload.max_rssi;
|
||||||
if (!payload.device_ids || payload.device_ids.length === 0) payload.device_ids = null;
|
if (!payload.device_ids || payload.device_ids.length === 0) payload.device_ids = null;
|
||||||
if (!payload.drone_types || payload.drone_types.length === 0) payload.drone_types = null;
|
if (!payload.drone_types || payload.drone_types.length === 0) payload.drone_types = null;
|
||||||
if (!payload.frequency_ranges || payload.frequency_ranges.length === 0) payload.frequency_ranges = null;
|
|
||||||
|
|
||||||
await api.post('/alerts/rules', payload);
|
await api.post('/alerts/rules', payload);
|
||||||
onSave();
|
onSave();
|
||||||
@@ -516,6 +537,15 @@ const CreateAlertRuleModal = ({ onClose, onSave }) => {
|
|||||||
}));
|
}));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleDeviceChange = (deviceId, checked) => {
|
||||||
|
setFormData(prev => ({
|
||||||
|
...prev,
|
||||||
|
device_ids: checked
|
||||||
|
? [...prev.device_ids, deviceId]
|
||||||
|
: prev.device_ids.filter(id => id !== deviceId)
|
||||||
|
}));
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="fixed inset-0 z-50 overflow-y-auto">
|
<div className="fixed inset-0 z-50 overflow-y-auto">
|
||||||
<div className="flex items-end justify-center min-h-screen pt-4 px-4 pb-20 text-center sm:block sm:p-0">
|
<div className="flex items-end justify-center min-h-screen pt-4 px-4 pb-20 text-center sm:block sm:p-0">
|
||||||
@@ -650,13 +680,7 @@ const CreateAlertRuleModal = ({ onClose, onSave }) => {
|
|||||||
<div className="text-xs text-gray-500 mb-2">
|
<div className="text-xs text-gray-500 mb-2">
|
||||||
Leave empty to monitor all drone types
|
Leave empty to monitor all drone types
|
||||||
</div>
|
</div>
|
||||||
{[
|
{droneTypes.map(droneType => (
|
||||||
{ id: 0, name: 'Consumer/Hobby' },
|
|
||||||
{ id: 1, name: 'Orlan/Military' },
|
|
||||||
{ id: 2, name: 'Professional/Commercial' },
|
|
||||||
{ id: 3, name: 'Racing/High-speed' },
|
|
||||||
{ id: 4, name: 'Unknown/Custom' }
|
|
||||||
].map(droneType => (
|
|
||||||
<label key={droneType.id} className="flex items-center">
|
<label key={droneType.id} className="flex items-center">
|
||||||
<input
|
<input
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
@@ -666,12 +690,48 @@ const CreateAlertRuleModal = ({ onClose, onSave }) => {
|
|||||||
/>
|
/>
|
||||||
<span className="ml-2 text-sm text-gray-700">
|
<span className="ml-2 text-sm text-gray-700">
|
||||||
{droneType.name}
|
{droneType.name}
|
||||||
{droneType.id === 1 && <span className="text-red-600 font-semibold"> (⚠️ High Threat)</span>}
|
<span className="text-xs text-gray-500 ml-1">({droneType.category})</span>
|
||||||
|
{droneType.threat_level === 'critical' && (
|
||||||
|
<span className="text-red-600 font-semibold ml-1">(⚠️ High Threat)</span>
|
||||||
|
)}
|
||||||
</span>
|
</span>
|
||||||
</label>
|
</label>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<label className="block text-sm font-medium text-gray-700 mb-2">
|
||||||
|
Device Selection
|
||||||
|
</label>
|
||||||
|
<div className="space-y-2">
|
||||||
|
<div className="text-xs text-gray-500 mb-2">
|
||||||
|
Leave empty to monitor all approved devices
|
||||||
|
</div>
|
||||||
|
{loadingData ? (
|
||||||
|
<div className="text-sm text-gray-500">Loading devices...</div>
|
||||||
|
) : devices.length === 0 ? (
|
||||||
|
<div className="text-sm text-gray-500">No devices available</div>
|
||||||
|
) : (
|
||||||
|
devices.filter(device => device.is_approved).map(device => (
|
||||||
|
<label key={device.id} className="flex items-center">
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
checked={formData.device_ids.includes(device.id)}
|
||||||
|
onChange={(e) => handleDeviceChange(device.id, e.target.checked)}
|
||||||
|
className="h-4 w-4 text-primary-600 focus:ring-primary-500 border-gray-300 rounded"
|
||||||
|
/>
|
||||||
|
<span className="ml-2 text-sm text-gray-700">
|
||||||
|
{device.name || `Device ${device.id}`}
|
||||||
|
<span className="text-xs text-gray-500 ml-1">
|
||||||
|
({device.location_description || 'No location'})
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
</label>
|
||||||
|
))
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user