Fix jwt-token
This commit is contained in:
@@ -1,12 +1,15 @@
|
||||
import React, { useState, useEffect } from 'react'
|
||||
import api from '../services/api'
|
||||
import toast from 'react-hot-toast'
|
||||
import {
|
||||
TrashIcon,
|
||||
ServerIcon,
|
||||
ChartBarIcon,
|
||||
ClockIcon,
|
||||
ExclamationTriangleIcon,
|
||||
CheckCircleIcon
|
||||
CheckCircleIcon,
|
||||
PlayIcon,
|
||||
EyeIcon
|
||||
} from '@heroicons/react/24/outline'
|
||||
|
||||
const DataRetentionMetrics = () => {
|
||||
@@ -14,6 +17,9 @@ const DataRetentionMetrics = () => {
|
||||
const [loading, setLoading] = useState(true)
|
||||
const [error, setError] = useState(null)
|
||||
const [lastUpdate, setLastUpdate] = useState(null)
|
||||
const [cleanupLoading, setCleanupLoading] = useState(false)
|
||||
const [previewData, setPreviewData] = useState(null)
|
||||
const [showPreview, setShowPreview] = useState(false)
|
||||
|
||||
useEffect(() => {
|
||||
loadDataRetentionMetrics()
|
||||
@@ -36,6 +42,42 @@ const DataRetentionMetrics = () => {
|
||||
}
|
||||
}
|
||||
|
||||
const loadCleanupPreview = async () => {
|
||||
try {
|
||||
setError(null)
|
||||
const response = await api.get('/data-retention/stats')
|
||||
setPreviewData(response.data.data)
|
||||
setShowPreview(true)
|
||||
} catch (error) {
|
||||
console.error('Error loading cleanup preview:', error)
|
||||
toast.error('Failed to load cleanup preview')
|
||||
}
|
||||
}
|
||||
|
||||
const executeCleanup = async () => {
|
||||
if (!window.confirm('Are you sure you want to execute data retention cleanup? This will permanently delete old data according to each tenant\'s retention policy.')) {
|
||||
return
|
||||
}
|
||||
|
||||
setCleanupLoading(true)
|
||||
try {
|
||||
// Note: This endpoint would need to be implemented in the backend
|
||||
const response = await api.post('/data-retention/cleanup')
|
||||
toast.success('Data retention cleanup initiated successfully')
|
||||
|
||||
// Refresh metrics after cleanup
|
||||
setTimeout(() => {
|
||||
loadDataRetentionMetrics()
|
||||
}, 2000)
|
||||
|
||||
} catch (error) {
|
||||
console.error('Error executing cleanup:', error)
|
||||
toast.error(error.response?.data?.message || 'Failed to execute cleanup')
|
||||
} finally {
|
||||
setCleanupLoading(false)
|
||||
}
|
||||
}
|
||||
|
||||
const formatUptime = (seconds) => {
|
||||
if (!seconds) return 'Unknown'
|
||||
const days = Math.floor(seconds / 86400)
|
||||
@@ -111,8 +153,36 @@ const DataRetentionMetrics = () => {
|
||||
<ExclamationTriangleIcon className="h-5 w-5 text-red-500 ml-2" />
|
||||
)}
|
||||
</div>
|
||||
<div className="text-sm text-gray-500">
|
||||
{lastUpdate && `Updated ${lastUpdate.toLocaleTimeString()}`}
|
||||
|
||||
<div className="flex items-center gap-4">
|
||||
<div className="text-sm text-gray-500">
|
||||
{lastUpdate && `Updated ${lastUpdate.toLocaleTimeString()}`}
|
||||
</div>
|
||||
|
||||
{/* Action Buttons */}
|
||||
{isConnected && (
|
||||
<div className="flex gap-2">
|
||||
<button
|
||||
onClick={loadCleanupPreview}
|
||||
className="px-3 py-1.5 bg-blue-100 text-blue-700 rounded-md hover:bg-blue-200 transition-colors text-sm flex items-center gap-1"
|
||||
>
|
||||
<EyeIcon className="h-4 w-4" />
|
||||
Preview Cleanup
|
||||
</button>
|
||||
<button
|
||||
onClick={executeCleanup}
|
||||
disabled={cleanupLoading}
|
||||
className="px-3 py-1.5 bg-red-100 text-red-700 rounded-md hover:bg-red-200 transition-colors text-sm flex items-center gap-1 disabled:opacity-50"
|
||||
>
|
||||
{cleanupLoading ? (
|
||||
<div className="animate-spin rounded-full h-4 w-4 border-b-2 border-red-700"></div>
|
||||
) : (
|
||||
<PlayIcon className="h-4 w-4" />
|
||||
)}
|
||||
{cleanupLoading ? 'Running...' : 'Run Cleanup'}
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -211,6 +281,78 @@ const DataRetentionMetrics = () => {
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Cleanup Preview Modal */}
|
||||
{showPreview && previewData && (
|
||||
<div className="fixed inset-0 bg-gray-600 bg-opacity-50 overflow-y-auto h-full w-full z-50">
|
||||
<div className="relative top-20 mx-auto p-5 border w-11/12 md:w-3/4 lg:w-1/2 shadow-lg rounded-md bg-white">
|
||||
<div className="flex items-center justify-between mb-4">
|
||||
<h3 className="text-lg font-medium">Data Retention Cleanup Preview</h3>
|
||||
<button
|
||||
onClick={() => setShowPreview(false)}
|
||||
className="text-gray-400 hover:text-gray-600"
|
||||
>
|
||||
<span className="sr-only">Close</span>
|
||||
✕
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div className="space-y-4">
|
||||
<p className="text-sm text-gray-600">
|
||||
This preview shows what data would be deleted based on each tenant's retention policy.
|
||||
</p>
|
||||
|
||||
{previewData.tenants && previewData.tenants.map((tenant, index) => (
|
||||
<div key={index} className="border rounded-lg p-4">
|
||||
<div className="flex items-center justify-between mb-2">
|
||||
<h4 className="font-medium">{tenant.name}</h4>
|
||||
<span className="text-sm text-gray-500">
|
||||
{tenant.retentionDays === -1 ? 'Unlimited' : `${tenant.retentionDays} days`}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
{tenant.retentionDays === -1 ? (
|
||||
<p className="text-sm text-gray-600">No data will be deleted (unlimited retention)</p>
|
||||
) : (
|
||||
<div className="grid grid-cols-3 gap-4 text-sm">
|
||||
<div>
|
||||
<span className="font-medium">Detections:</span>
|
||||
<span className="ml-2">{tenant.toDelete?.detections || 0}</span>
|
||||
</div>
|
||||
<div>
|
||||
<span className="font-medium">Heartbeats:</span>
|
||||
<span className="ml-2">{tenant.toDelete?.heartbeats || 0}</span>
|
||||
</div>
|
||||
<div>
|
||||
<span className="font-medium">Logs:</span>
|
||||
<span className="ml-2">{tenant.toDelete?.logs || 0}</span>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
|
||||
<div className="flex justify-end gap-3 pt-4 border-t">
|
||||
<button
|
||||
onClick={() => setShowPreview(false)}
|
||||
className="px-4 py-2 bg-gray-100 text-gray-700 rounded-md hover:bg-gray-200"
|
||||
>
|
||||
Cancel
|
||||
</button>
|
||||
<button
|
||||
onClick={() => {
|
||||
setShowPreview(false)
|
||||
executeCleanup()
|
||||
}}
|
||||
className="px-4 py-2 bg-red-600 text-white rounded-md hover:bg-red-700"
|
||||
>
|
||||
Execute Cleanup
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user