Update various configuration files, components, and assets; enhance notification system and API endpoints; improve documentation and styles across the application.
This commit is contained in:
803
pages/notification/queue/persistence.vue
Normal file
803
pages/notification/queue/persistence.vue
Normal file
@@ -0,0 +1,803 @@
|
||||
<template>
|
||||
<div>
|
||||
<LayoutsBreadcrumb />
|
||||
|
||||
<!-- Header Section -->
|
||||
<rs-card class="mb-6">
|
||||
<template #header>
|
||||
<div class="flex items-center justify-between">
|
||||
<div class="flex items-center">
|
||||
<Icon class="mr-2 text-primary" name="ic:outline-storage"></Icon>
|
||||
<h1 class="text-xl font-bold text-primary">Queue Persistence Configuration</h1>
|
||||
</div>
|
||||
<div class="flex items-center gap-3">
|
||||
<div class="flex items-center">
|
||||
<div class="w-2 h-2 bg-green-500 rounded-full mr-2 animate-pulse"></div>
|
||||
<span class="text-sm text-gray-600">Persistence Active</span>
|
||||
</div>
|
||||
<rs-button variant="outline" size="sm" @click="testPersistence">
|
||||
<Icon class="mr-1" name="ic:outline-bug-report"></Icon>
|
||||
Test Recovery
|
||||
</rs-button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<template #body>
|
||||
<p class="text-gray-600">
|
||||
Configure queue data persistence to ensure notifications survive system restarts and failures.
|
||||
Critical for maintaining queue integrity and preventing message loss during system maintenance.
|
||||
</p>
|
||||
</template>
|
||||
</rs-card>
|
||||
|
||||
<!-- Persistence Status Overview -->
|
||||
<div class="grid grid-cols-1 lg:grid-cols-2 xl:grid-cols-4 gap-6 mb-6">
|
||||
<rs-card
|
||||
v-for="(metric, index) in persistenceMetrics"
|
||||
:key="index"
|
||||
class="transition-all duration-300 hover:shadow-lg"
|
||||
>
|
||||
<div class="pt-5 pb-3 px-5 flex items-center gap-4">
|
||||
<div
|
||||
class="p-4 flex justify-center items-center rounded-2xl"
|
||||
:class="metric.bgColor"
|
||||
>
|
||||
<Icon class="text-2xl" :class="metric.iconColor" :name="metric.icon"></Icon>
|
||||
</div>
|
||||
<div class="flex-1 truncate">
|
||||
<span class="block font-bold text-2xl leading-tight" :class="metric.valueColor">
|
||||
{{ metric.value }}
|
||||
</span>
|
||||
<span class="text-sm font-medium text-gray-600">
|
||||
{{ metric.title }}
|
||||
</span>
|
||||
<div class="flex items-center mt-1" v-if="metric.status">
|
||||
<div
|
||||
class="w-2 h-2 rounded-full mr-1"
|
||||
:class="{
|
||||
'bg-green-500': metric.status === 'healthy',
|
||||
'bg-yellow-500': metric.status === 'warning',
|
||||
'bg-red-500': metric.status === 'error'
|
||||
}"
|
||||
></div>
|
||||
<span class="text-xs capitalize" :class="{
|
||||
'text-green-600': metric.status === 'healthy',
|
||||
'text-yellow-600': metric.status === 'warning',
|
||||
'text-red-600': metric.status === 'error'
|
||||
}">
|
||||
{{ metric.status }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</rs-card>
|
||||
</div>
|
||||
|
||||
<!-- Storage Configuration -->
|
||||
<div class="grid grid-cols-1 lg:grid-cols-2 gap-6 mb-6">
|
||||
<!-- Primary Storage -->
|
||||
<rs-card>
|
||||
<template #header>
|
||||
<div class="flex items-center justify-between">
|
||||
<div class="flex items-center">
|
||||
<Icon class="mr-2 text-primary" name="ic:outline-database"></Icon>
|
||||
<h3 class="text-lg font-semibold text-primary">Primary Storage Configuration</h3>
|
||||
</div>
|
||||
<rs-button variant="outline" size="sm" @click="showStorageModal = true">
|
||||
<Icon class="mr-1" name="ic:outline-settings"></Icon>
|
||||
Configure
|
||||
</rs-button>
|
||||
</div>
|
||||
</template>
|
||||
<template #body>
|
||||
<div class="space-y-4">
|
||||
<!-- Storage Type -->
|
||||
<div class="flex items-center justify-between p-3 bg-gray-50 rounded-lg">
|
||||
<div>
|
||||
<p class="font-medium">Storage Type</p>
|
||||
<p class="text-sm text-gray-600">{{ storageConfig.type }}</p>
|
||||
</div>
|
||||
<div class="text-right">
|
||||
<span
|
||||
class="inline-flex px-2 py-1 text-xs font-semibold rounded-full"
|
||||
:class="{
|
||||
'bg-green-100 text-green-800': storageConfig.status === 'connected',
|
||||
'bg-red-100 text-red-800': storageConfig.status === 'disconnected',
|
||||
'bg-yellow-100 text-yellow-800': storageConfig.status === 'reconnecting'
|
||||
}"
|
||||
>
|
||||
{{ storageConfig.status }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Connection Details -->
|
||||
<div class="grid grid-cols-2 gap-4">
|
||||
<div class="text-center p-3 bg-blue-50 rounded-lg">
|
||||
<p class="text-sm text-gray-600">Connection Pool</p>
|
||||
<p class="font-bold text-blue-600">{{ storageConfig.connectionPool }}/{{ storageConfig.maxConnections }}</p>
|
||||
</div>
|
||||
<div class="text-center p-3 bg-green-50 rounded-lg">
|
||||
<p class="text-sm text-gray-600">Response Time</p>
|
||||
<p class="font-bold text-green-600">{{ storageConfig.responseTime }}ms</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Storage Metrics -->
|
||||
<div class="space-y-2">
|
||||
<div class="flex justify-between">
|
||||
<span class="text-sm text-gray-600">Used Space</span>
|
||||
<span class="text-sm font-medium">{{ storageConfig.usedSpace }} / {{ storageConfig.totalSpace }}</span>
|
||||
</div>
|
||||
<div class="w-full bg-gray-200 rounded-full h-2">
|
||||
<div
|
||||
class="bg-blue-600 h-2 rounded-full"
|
||||
:style="{ width: storageConfig.usagePercentage + '%' }"
|
||||
></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Last Backup -->
|
||||
<div class="flex items-center justify-between p-3 bg-green-50 rounded-lg">
|
||||
<div>
|
||||
<p class="font-medium text-green-800">Last Backup</p>
|
||||
<p class="text-sm text-green-600">{{ storageConfig.lastBackup }}</p>
|
||||
</div>
|
||||
<Icon class="text-green-600" name="ic:outline-backup"></Icon>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</rs-card>
|
||||
|
||||
<!-- Backup & Recovery -->
|
||||
<rs-card>
|
||||
<template #header>
|
||||
<div class="flex items-center justify-between">
|
||||
<div class="flex items-center">
|
||||
<Icon class="mr-2 text-primary" name="ic:outline-backup"></Icon>
|
||||
<h3 class="text-lg font-semibold text-primary">Backup & Recovery</h3>
|
||||
</div>
|
||||
<rs-button variant="outline" size="sm" @click="createBackup">
|
||||
<Icon class="mr-1" name="ic:outline-backup"></Icon>
|
||||
Create Backup
|
||||
</rs-button>
|
||||
</div>
|
||||
</template>
|
||||
<template #body>
|
||||
<div class="space-y-4">
|
||||
<!-- Backup Schedule -->
|
||||
<div class="p-3 bg-gray-50 rounded-lg">
|
||||
<div class="flex items-center justify-between mb-2">
|
||||
<p class="font-medium">Automatic Backups</p>
|
||||
<div class="flex items-center">
|
||||
<input
|
||||
type="checkbox"
|
||||
v-model="backupConfig.autoBackupEnabled"
|
||||
class="mr-2"
|
||||
@change="updateBackupConfig"
|
||||
>
|
||||
<span class="text-sm">{{ backupConfig.autoBackupEnabled ? 'Enabled' : 'Disabled' }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<p class="text-sm text-gray-600">
|
||||
Frequency: {{ backupConfig.frequency }} |
|
||||
Retention: {{ backupConfig.retention }} days
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<!-- Recent Backups -->
|
||||
<div>
|
||||
<h4 class="font-medium text-gray-700 mb-2">Recent Backups</h4>
|
||||
<div class="space-y-2">
|
||||
<div
|
||||
v-for="(backup, index) in recentBackups"
|
||||
:key="index"
|
||||
class="flex items-center justify-between p-2 bg-gray-50 rounded"
|
||||
>
|
||||
<div class="flex items-center">
|
||||
<Icon
|
||||
class="mr-2 text-sm"
|
||||
:class="{
|
||||
'text-green-500': backup.status === 'completed',
|
||||
'text-yellow-500': backup.status === 'in-progress',
|
||||
'text-red-500': backup.status === 'failed'
|
||||
}"
|
||||
:name="backup.status === 'completed' ? 'ic:outline-check-circle' :
|
||||
backup.status === 'in-progress' ? 'ic:outline-hourglass-empty' :
|
||||
'ic:outline-error'"
|
||||
></Icon>
|
||||
<div>
|
||||
<p class="text-sm font-medium">{{ backup.name }}</p>
|
||||
<p class="text-xs text-gray-500">{{ backup.size }} • {{ backup.timestamp }}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-center gap-1">
|
||||
<rs-button
|
||||
variant="outline"
|
||||
size="xs"
|
||||
@click="downloadBackup(backup)"
|
||||
:disabled="backup.status !== 'completed'"
|
||||
>
|
||||
<Icon class="text-xs" name="ic:outline-download"></Icon>
|
||||
</rs-button>
|
||||
<rs-button
|
||||
variant="outline"
|
||||
size="xs"
|
||||
@click="restoreBackup(backup)"
|
||||
:disabled="backup.status !== 'completed'"
|
||||
>
|
||||
<Icon class="text-xs" name="ic:outline-restore"></Icon>
|
||||
</rs-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Recovery Test -->
|
||||
<div class="p-3 bg-yellow-50 rounded-lg">
|
||||
<div class="flex items-center justify-between">
|
||||
<div>
|
||||
<p class="font-medium text-yellow-800">Recovery Test</p>
|
||||
<p class="text-sm text-yellow-600">Last test: {{ recoveryTest.lastTest }}</p>
|
||||
</div>
|
||||
<rs-button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
@click="runRecoveryTest"
|
||||
>
|
||||
Run Test
|
||||
</rs-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</rs-card>
|
||||
</div>
|
||||
|
||||
<!-- Queue Recovery Status -->
|
||||
<rs-card class="mb-6">
|
||||
<template #header>
|
||||
<div class="flex items-center justify-between">
|
||||
<div class="flex items-center">
|
||||
<Icon class="mr-2 text-primary" name="ic:outline-restore"></Icon>
|
||||
<h3 class="text-lg font-semibold text-primary">Queue Recovery Status</h3>
|
||||
</div>
|
||||
<div class="flex items-center gap-3">
|
||||
<span class="text-sm text-gray-600">Last System Restart: {{ lastSystemRestart }}</span>
|
||||
<rs-button variant="outline" size="sm" @click="showRecoveryDetails = true">
|
||||
<Icon class="mr-1" name="ic:outline-info"></Icon>
|
||||
View Details
|
||||
</rs-button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<template #body>
|
||||
<div class="grid grid-cols-1 lg:grid-cols-3 gap-6">
|
||||
<!-- Recovery Statistics -->
|
||||
<div class="space-y-4">
|
||||
<h4 class="font-medium text-gray-700">Recovery Statistics</h4>
|
||||
<div class="space-y-3">
|
||||
<div class="flex justify-between">
|
||||
<span class="text-sm text-gray-600">Jobs Recovered</span>
|
||||
<span class="font-medium text-green-600">{{ recoveryStats.jobsRecovered.toLocaleString() }}</span>
|
||||
</div>
|
||||
<div class="flex justify-between">
|
||||
<span class="text-sm text-gray-600">Jobs Lost</span>
|
||||
<span class="font-medium text-red-600">{{ recoveryStats.jobsLost }}</span>
|
||||
</div>
|
||||
<div class="flex justify-between">
|
||||
<span class="text-sm text-gray-600">Recovery Time</span>
|
||||
<span class="font-medium">{{ recoveryStats.recoveryTime }}</span>
|
||||
</div>
|
||||
<div class="flex justify-between">
|
||||
<span class="text-sm text-gray-600">Success Rate</span>
|
||||
<span class="font-medium text-blue-600">{{ recoveryStats.successRate }}%</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Recovery Timeline -->
|
||||
<div class="space-y-4">
|
||||
<h4 class="font-medium text-gray-700">Recovery Timeline</h4>
|
||||
<div class="space-y-3">
|
||||
<div
|
||||
v-for="(event, index) in recoveryTimeline"
|
||||
:key="index"
|
||||
class="flex items-start"
|
||||
>
|
||||
<div
|
||||
class="w-3 h-3 rounded-full mt-1 mr-3"
|
||||
:class="{
|
||||
'bg-green-500': event.status === 'completed',
|
||||
'bg-yellow-500': event.status === 'in-progress',
|
||||
'bg-red-500': event.status === 'failed'
|
||||
}"
|
||||
></div>
|
||||
<div>
|
||||
<p class="text-sm font-medium">{{ event.action }}</p>
|
||||
<p class="text-xs text-gray-500">{{ event.timestamp }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Queue State -->
|
||||
<div class="space-y-4">
|
||||
<h4 class="font-medium text-gray-700">Current Queue State</h4>
|
||||
<div class="space-y-3">
|
||||
<div
|
||||
v-for="(queue, index) in queueStates"
|
||||
:key="index"
|
||||
class="p-3 bg-gray-50 rounded-lg"
|
||||
>
|
||||
<div class="flex items-center justify-between mb-1">
|
||||
<span class="text-sm font-medium">{{ queue.name }}</span>
|
||||
<span
|
||||
class="text-xs px-2 py-1 rounded-full"
|
||||
:class="{
|
||||
'bg-green-100 text-green-800': queue.status === 'healthy',
|
||||
'bg-yellow-100 text-yellow-800': queue.status === 'recovering',
|
||||
'bg-red-100 text-red-800': queue.status === 'error'
|
||||
}"
|
||||
>
|
||||
{{ queue.status }}
|
||||
</span>
|
||||
</div>
|
||||
<div class="flex justify-between text-xs text-gray-600">
|
||||
<span>{{ queue.count }} jobs</span>
|
||||
<span>{{ queue.lastProcessed }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</rs-card>
|
||||
|
||||
<!-- Persistence Configuration -->
|
||||
<rs-card>
|
||||
<template #header>
|
||||
<div class="flex items-center justify-between">
|
||||
<div class="flex items-center">
|
||||
<Icon class="mr-2 text-primary" name="ic:outline-settings"></Icon>
|
||||
<h3 class="text-lg font-semibold text-primary">Persistence Settings</h3>
|
||||
</div>
|
||||
<rs-button @click="savePersistenceConfig">
|
||||
<Icon class="mr-1" name="ic:outline-save"></Icon>
|
||||
Save Configuration
|
||||
</rs-button>
|
||||
</div>
|
||||
</template>
|
||||
<template #body>
|
||||
<div class="grid grid-cols-1 lg:grid-cols-2 gap-6">
|
||||
<!-- General Settings -->
|
||||
<div class="space-y-4">
|
||||
<h4 class="font-medium text-gray-700">General Settings</h4>
|
||||
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-700 mb-2">Persistence Mode</label>
|
||||
<select v-model="persistenceConfig.mode" class="w-full p-2 border border-gray-300 rounded-md">
|
||||
<option value="immediate">Immediate (Every job)</option>
|
||||
<option value="batch">Batch (Every N jobs)</option>
|
||||
<option value="interval">Interval (Every N seconds)</option>
|
||||
<option value="hybrid">Hybrid (Immediate + Batch)</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div v-if="persistenceConfig.mode === 'batch'">
|
||||
<label class="block text-sm font-medium text-gray-700 mb-2">Batch Size</label>
|
||||
<input
|
||||
type="number"
|
||||
v-model="persistenceConfig.batchSize"
|
||||
class="w-full p-2 border border-gray-300 rounded-md"
|
||||
min="1"
|
||||
>
|
||||
</div>
|
||||
|
||||
<div v-if="persistenceConfig.mode === 'interval'">
|
||||
<label class="block text-sm font-medium text-gray-700 mb-2">Interval (seconds)</label>
|
||||
<input
|
||||
type="number"
|
||||
v-model="persistenceConfig.interval"
|
||||
class="w-full p-2 border border-gray-300 rounded-md"
|
||||
min="1"
|
||||
>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-700 mb-2">Data Retention (days)</label>
|
||||
<input
|
||||
type="number"
|
||||
v-model="persistenceConfig.retentionDays"
|
||||
class="w-full p-2 border border-gray-300 rounded-md"
|
||||
min="1"
|
||||
>
|
||||
<p class="text-xs text-gray-500 mt-1">How long to keep completed job data</p>
|
||||
</div>
|
||||
|
||||
<div class="flex items-center">
|
||||
<input
|
||||
type="checkbox"
|
||||
v-model="persistenceConfig.compressData"
|
||||
class="mr-2"
|
||||
>
|
||||
<span class="text-sm text-gray-700">Enable data compression</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Recovery Settings -->
|
||||
<div class="space-y-4">
|
||||
<h4 class="font-medium text-gray-700">Recovery Settings</h4>
|
||||
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-700 mb-2">Recovery Strategy</label>
|
||||
<select v-model="persistenceConfig.recoveryStrategy" class="w-full p-2 border border-gray-300 rounded-md">
|
||||
<option value="full">Full Recovery (All jobs)</option>
|
||||
<option value="priority">Priority Recovery (High priority first)</option>
|
||||
<option value="recent">Recent Recovery (Last N hours)</option>
|
||||
<option value="selective">Selective Recovery (Manual selection)</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div v-if="persistenceConfig.recoveryStrategy === 'recent'">
|
||||
<label class="block text-sm font-medium text-gray-700 mb-2">Recovery Window (hours)</label>
|
||||
<input
|
||||
type="number"
|
||||
v-model="persistenceConfig.recoveryWindow"
|
||||
class="w-full p-2 border border-gray-300 rounded-md"
|
||||
min="1"
|
||||
>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-700 mb-2">Max Recovery Time (seconds)</label>
|
||||
<input
|
||||
type="number"
|
||||
v-model="persistenceConfig.maxRecoveryTime"
|
||||
class="w-full p-2 border border-gray-300 rounded-md"
|
||||
min="1"
|
||||
>
|
||||
<p class="text-xs text-gray-500 mt-1">Maximum time allowed for recovery process</p>
|
||||
</div>
|
||||
|
||||
<div class="flex items-center">
|
||||
<input
|
||||
type="checkbox"
|
||||
v-model="persistenceConfig.autoRecovery"
|
||||
class="mr-2"
|
||||
>
|
||||
<span class="text-sm text-gray-700">Enable automatic recovery on startup</span>
|
||||
</div>
|
||||
|
||||
<div class="flex items-center">
|
||||
<input
|
||||
type="checkbox"
|
||||
v-model="persistenceConfig.validateRecovery"
|
||||
class="mr-2"
|
||||
>
|
||||
<span class="text-sm text-gray-700">Validate recovered jobs before processing</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</rs-card>
|
||||
|
||||
<!-- Storage Configuration Modal -->
|
||||
<rs-modal v-model="showStorageModal" title="Storage Configuration">
|
||||
<div class="space-y-6">
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-700 mb-2">Storage Type</label>
|
||||
<select v-model="storageConfig.type" class="w-full p-2 border border-gray-300 rounded-md">
|
||||
<option value="Redis">Redis</option>
|
||||
<option value="PostgreSQL">PostgreSQL</option>
|
||||
<option value="MongoDB">MongoDB</option>
|
||||
<option value="MySQL">MySQL</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-700 mb-2">Connection String</label>
|
||||
<input
|
||||
type="text"
|
||||
v-model="storageConfig.connectionString"
|
||||
class="w-full p-2 border border-gray-300 rounded-md"
|
||||
placeholder="redis://localhost:6379"
|
||||
>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-2 gap-4">
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-700 mb-2">Max Connections</label>
|
||||
<input
|
||||
type="number"
|
||||
v-model="storageConfig.maxConnections"
|
||||
class="w-full p-2 border border-gray-300 rounded-md"
|
||||
min="1"
|
||||
>
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-700 mb-2">Connection Timeout (ms)</label>
|
||||
<input
|
||||
type="number"
|
||||
v-model="storageConfig.connectionTimeout"
|
||||
class="w-full p-2 border border-gray-300 rounded-md"
|
||||
min="100"
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<template #footer>
|
||||
<div class="flex justify-end gap-3">
|
||||
<rs-button variant="outline" @click="showStorageModal = false">
|
||||
Cancel
|
||||
</rs-button>
|
||||
<rs-button @click="saveStorageConfig">
|
||||
Save Configuration
|
||||
</rs-button>
|
||||
</div>
|
||||
</template>
|
||||
</rs-modal>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
definePageMeta({
|
||||
title: "Queue Persistence",
|
||||
middleware: ["auth"],
|
||||
requiresAuth: true,
|
||||
breadcrumb: [
|
||||
{
|
||||
name: "Notification",
|
||||
path: "/notification",
|
||||
},
|
||||
{
|
||||
name: "Queue & Scheduler",
|
||||
path: "/notification/queue-scheduler",
|
||||
},
|
||||
{
|
||||
name: "Persistence",
|
||||
path: "/notification/queue-scheduler/persistence",
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
// Reactive data
|
||||
const showStorageModal = ref(false);
|
||||
const showRecoveryDetails = ref(false);
|
||||
|
||||
// Persistence metrics
|
||||
const persistenceMetrics = ref([
|
||||
{
|
||||
title: "Storage Health",
|
||||
value: "Healthy",
|
||||
icon: "ic:outline-health-and-safety",
|
||||
bgColor: "bg-green-100",
|
||||
iconColor: "text-green-600",
|
||||
valueColor: "text-green-600",
|
||||
status: "healthy"
|
||||
},
|
||||
{
|
||||
title: "Persisted Jobs",
|
||||
value: "847,293",
|
||||
icon: "ic:outline-storage",
|
||||
bgColor: "bg-blue-100",
|
||||
iconColor: "text-blue-600",
|
||||
valueColor: "text-blue-600"
|
||||
},
|
||||
{
|
||||
title: "Recovery Rate",
|
||||
value: "99.97%",
|
||||
icon: "ic:outline-restore",
|
||||
bgColor: "bg-purple-100",
|
||||
iconColor: "text-purple-600",
|
||||
valueColor: "text-purple-600",
|
||||
status: "healthy"
|
||||
},
|
||||
{
|
||||
title: "Storage Usage",
|
||||
value: "67%",
|
||||
icon: "ic:outline-pie-chart",
|
||||
bgColor: "bg-yellow-100",
|
||||
iconColor: "text-yellow-600",
|
||||
valueColor: "text-yellow-600",
|
||||
status: "warning"
|
||||
}
|
||||
]);
|
||||
|
||||
// Storage configuration
|
||||
const storageConfig = ref({
|
||||
type: "Redis",
|
||||
status: "connected",
|
||||
connectionPool: 8,
|
||||
maxConnections: 20,
|
||||
responseTime: 2.3,
|
||||
usedSpace: "2.4 GB",
|
||||
totalSpace: "10 GB",
|
||||
usagePercentage: 67,
|
||||
lastBackup: "2 hours ago",
|
||||
connectionString: "redis://localhost:6379",
|
||||
connectionTimeout: 5000
|
||||
});
|
||||
|
||||
// Backup configuration
|
||||
const backupConfig = ref({
|
||||
autoBackupEnabled: true,
|
||||
frequency: "Every 6 hours",
|
||||
retention: 30
|
||||
});
|
||||
|
||||
// Recent backups
|
||||
const recentBackups = ref([
|
||||
{
|
||||
name: "queue-backup-2024-01-15-14-30",
|
||||
size: "1.2 GB",
|
||||
timestamp: "2 hours ago",
|
||||
status: "completed"
|
||||
},
|
||||
{
|
||||
name: "queue-backup-2024-01-15-08-30",
|
||||
size: "1.1 GB",
|
||||
timestamp: "8 hours ago",
|
||||
status: "completed"
|
||||
},
|
||||
{
|
||||
name: "queue-backup-2024-01-15-02-30",
|
||||
size: "1.0 GB",
|
||||
timestamp: "14 hours ago",
|
||||
status: "completed"
|
||||
},
|
||||
{
|
||||
name: "queue-backup-2024-01-14-20-30",
|
||||
size: "987 MB",
|
||||
timestamp: "20 hours ago",
|
||||
status: "completed"
|
||||
}
|
||||
]);
|
||||
|
||||
// Recovery test
|
||||
const recoveryTest = ref({
|
||||
lastTest: "3 days ago",
|
||||
status: "passed"
|
||||
});
|
||||
|
||||
// System restart info
|
||||
const lastSystemRestart = ref("5 days ago");
|
||||
|
||||
// Recovery statistics
|
||||
const recoveryStats = ref({
|
||||
jobsRecovered: 15847,
|
||||
jobsLost: 3,
|
||||
recoveryTime: "2.3 seconds",
|
||||
successRate: 99.97
|
||||
});
|
||||
|
||||
// Recovery timeline
|
||||
const recoveryTimeline = ref([
|
||||
{
|
||||
action: "System startup detected",
|
||||
timestamp: "5 days ago, 09:15:23",
|
||||
status: "completed"
|
||||
},
|
||||
{
|
||||
action: "Storage connection established",
|
||||
timestamp: "5 days ago, 09:15:24",
|
||||
status: "completed"
|
||||
},
|
||||
{
|
||||
action: "Queue data recovery initiated",
|
||||
timestamp: "5 days ago, 09:15:25",
|
||||
status: "completed"
|
||||
},
|
||||
{
|
||||
action: "15,847 jobs recovered successfully",
|
||||
timestamp: "5 days ago, 09:15:27",
|
||||
status: "completed"
|
||||
},
|
||||
{
|
||||
action: "Queue processing resumed",
|
||||
timestamp: "5 days ago, 09:15:28",
|
||||
status: "completed"
|
||||
}
|
||||
]);
|
||||
|
||||
// Queue states
|
||||
const queueStates = ref([
|
||||
{
|
||||
name: "High Priority",
|
||||
count: 234,
|
||||
status: "healthy",
|
||||
lastProcessed: "2 seconds ago"
|
||||
},
|
||||
{
|
||||
name: "Medium Priority",
|
||||
count: 1847,
|
||||
status: "healthy",
|
||||
lastProcessed: "1 second ago"
|
||||
},
|
||||
{
|
||||
name: "Low Priority",
|
||||
count: 3421,
|
||||
status: "healthy",
|
||||
lastProcessed: "5 seconds ago"
|
||||
},
|
||||
{
|
||||
name: "Bulk Operations",
|
||||
count: 2502,
|
||||
status: "recovering",
|
||||
lastProcessed: "30 seconds ago"
|
||||
}
|
||||
]);
|
||||
|
||||
// Persistence configuration
|
||||
const persistenceConfig = ref({
|
||||
mode: "hybrid",
|
||||
batchSize: 100,
|
||||
interval: 30,
|
||||
retentionDays: 30,
|
||||
compressData: true,
|
||||
recoveryStrategy: "priority",
|
||||
recoveryWindow: 24,
|
||||
maxRecoveryTime: 300,
|
||||
autoRecovery: true,
|
||||
validateRecovery: true
|
||||
});
|
||||
|
||||
// Methods
|
||||
const testPersistence = () => {
|
||||
console.log('Running persistence test...');
|
||||
// Simulate persistence test
|
||||
};
|
||||
|
||||
const createBackup = () => {
|
||||
console.log('Creating backup...');
|
||||
// Add new backup to the list
|
||||
const now = new Date();
|
||||
const timestamp = now.toISOString().slice(0, 19).replace(/:/g, '-');
|
||||
recentBackups.value.unshift({
|
||||
name: `queue-backup-${timestamp}`,
|
||||
size: "1.3 GB",
|
||||
timestamp: "Just now",
|
||||
status: "in-progress"
|
||||
});
|
||||
|
||||
// Simulate completion after 3 seconds
|
||||
setTimeout(() => {
|
||||
recentBackups.value[0].status = "completed";
|
||||
}, 3000);
|
||||
};
|
||||
|
||||
const downloadBackup = (backup) => {
|
||||
console.log('Downloading backup:', backup.name);
|
||||
// Simulate download
|
||||
};
|
||||
|
||||
const restoreBackup = (backup) => {
|
||||
console.log('Restoring backup:', backup.name);
|
||||
// Simulate restore
|
||||
};
|
||||
|
||||
const runRecoveryTest = () => {
|
||||
console.log('Running recovery test...');
|
||||
recoveryTest.value.lastTest = "Just now";
|
||||
// Simulate test
|
||||
};
|
||||
|
||||
const updateBackupConfig = () => {
|
||||
console.log('Updating backup configuration:', backupConfig.value);
|
||||
// Save backup config
|
||||
};
|
||||
|
||||
const savePersistenceConfig = () => {
|
||||
console.log('Saving persistence configuration:', persistenceConfig.value);
|
||||
// Save persistence config
|
||||
};
|
||||
|
||||
const saveStorageConfig = () => {
|
||||
console.log('Saving storage configuration:', storageConfig.value);
|
||||
showStorageModal.value = false;
|
||||
// Save storage config
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped></style>
|
||||
Reference in New Issue
Block a user