Skip to content

Commit d44374d

Browse files
mrveissclaude
andcommitted
feat(frontend): Add Redis optimization panel to code intelligence
- Add RedisOptimizationPanel.vue for Redis performance insights 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1 parent b74efeb commit d44374d

File tree

1 file changed

+153
-0
lines changed

1 file changed

+153
-0
lines changed
Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
<template>
2+
<div class="redis-optimization-panel">
3+
<!-- Summary Header -->
4+
<div class="bg-white rounded-lg shadow-md p-6 mb-6">
5+
<div class="flex flex-wrap items-center justify-between">
6+
<div>
7+
<h2 class="text-xl font-semibold text-blueGray-700">Redis Optimizations</h2>
8+
<p class="text-sm text-blueGray-500 mt-1">
9+
{{ optimizations.length }} optimization opportunities found
10+
</p>
11+
</div>
12+
<div class="flex items-center space-x-4 mt-4 sm:mt-0">
13+
<select
14+
v-model="categoryFilter"
15+
class="px-3 py-2 border border-blueGray-300 rounded-lg text-sm focus:ring-2 focus:ring-indigo-500"
16+
>
17+
<option value="all">All Types</option>
18+
<option value="pipeline">Pipeline</option>
19+
<option value="lua_script">Lua Script</option>
20+
<option value="data_structure">Data Structure</option>
21+
<option value="connection">Connection</option>
22+
<option value="cache">Cache</option>
23+
</select>
24+
<button
25+
@click="$emit('refresh')"
26+
:disabled="loading"
27+
class="px-4 py-2 text-indigo-600 hover:text-indigo-800 flex items-center"
28+
>
29+
<i class="fas fa-sync-alt mr-2" :class="{ 'animate-spin': loading }"></i>
30+
Refresh
31+
</button>
32+
</div>
33+
</div>
34+
</div>
35+
36+
<!-- Loading State -->
37+
<div v-if="loading" class="bg-white rounded-lg shadow-md p-12 text-center">
38+
<i class="fas fa-spinner fa-spin text-4xl text-indigo-500 mb-4"></i>
39+
<p class="text-blueGray-600">Analyzing Redis usage patterns...</p>
40+
</div>
41+
42+
<!-- Empty State -->
43+
<div v-else-if="filteredOptimizations.length === 0" class="bg-white rounded-lg shadow-md p-12 text-center">
44+
<i class="fas fa-database text-4xl text-green-500 mb-4"></i>
45+
<p class="text-lg font-medium text-blueGray-700">No Redis optimizations needed</p>
46+
<p class="text-sm text-blueGray-500 mt-2">Redis usage patterns look optimal!</p>
47+
</div>
48+
49+
<!-- Optimizations List -->
50+
<div v-else class="space-y-4">
51+
<div
52+
v-for="(opt, index) in filteredOptimizations"
53+
:key="index"
54+
class="bg-white rounded-lg shadow-md p-6 border-l-4"
55+
:class="getSeverityBorderClass(opt.severity)"
56+
>
57+
<div class="flex items-center flex-wrap gap-2 mb-2">
58+
<span
59+
class="px-2 py-1 text-xs font-medium rounded uppercase"
60+
:class="getSeverityBadgeClass(opt.severity)"
61+
>
62+
{{ opt.severity }}
63+
</span>
64+
<span class="text-sm font-medium text-blueGray-700">
65+
{{ formatOptType(opt.optimization_type) }}
66+
</span>
67+
<span
68+
v-if="opt.category"
69+
class="px-2 py-1 text-xs bg-purple-100 text-purple-700 rounded"
70+
>
71+
{{ opt.category }}
72+
</span>
73+
</div>
74+
<p class="text-sm text-blueGray-600">{{ opt.description }}</p>
75+
<div class="mt-3 flex items-center text-sm text-blueGray-500">
76+
<i class="fas fa-file-code mr-2"></i>
77+
<span class="font-mono">{{ formatFilePath(opt.file_path) }}</span>
78+
<span v-if="opt.line" class="ml-2">:{{ opt.line }}</span>
79+
</div>
80+
<div v-if="opt.code_snippet" class="mt-3 p-3 bg-blueGray-50 rounded-lg font-mono text-xs overflow-x-auto">
81+
<pre>{{ opt.code_snippet }}</pre>
82+
</div>
83+
<div v-if="opt.recommendation" class="mt-3 p-3 bg-green-50 rounded-lg border border-green-200">
84+
<p class="text-sm text-green-800">
85+
<i class="fas fa-lightbulb mr-2"></i>{{ opt.recommendation }}
86+
</p>
87+
</div>
88+
</div>
89+
</div>
90+
</div>
91+
</template>
92+
93+
<script setup lang="ts">
94+
import { ref, computed } from 'vue'
95+
96+
interface Optimization {
97+
severity: string
98+
optimization_type: string
99+
category?: string
100+
description: string
101+
file_path: string
102+
line?: number
103+
code_snippet?: string
104+
recommendation?: string
105+
}
106+
107+
interface Props {
108+
optimizations: Optimization[]
109+
loading: boolean
110+
summary: any
111+
}
112+
113+
const props = defineProps<Props>()
114+
defineEmits<{ 'scan-file': [path: string]; 'refresh': [] }>()
115+
116+
const categoryFilter = ref('all')
117+
118+
const filteredOptimizations = computed(() => {
119+
if (categoryFilter.value === 'all') return props.optimizations
120+
return props.optimizations.filter(o => o.category === categoryFilter.value)
121+
})
122+
123+
function getSeverityBorderClass(severity: string): string {
124+
const classes: Record<string, string> = {
125+
critical: 'border-red-500', high: 'border-orange-500',
126+
medium: 'border-yellow-500', low: 'border-blue-500', info: 'border-gray-400'
127+
}
128+
return classes[severity] || 'border-gray-300'
129+
}
130+
131+
function getSeverityBadgeClass(severity: string): string {
132+
const classes: Record<string, string> = {
133+
critical: 'bg-red-100 text-red-800', high: 'bg-orange-100 text-orange-800',
134+
medium: 'bg-yellow-100 text-yellow-800', low: 'bg-blue-100 text-blue-800',
135+
info: 'bg-gray-100 text-gray-800'
136+
}
137+
return classes[severity] || 'bg-gray-100 text-gray-800'
138+
}
139+
140+
function formatOptType(type: string): string {
141+
return type?.split('_').map(w => w.charAt(0).toUpperCase() + w.slice(1)).join(' ') || 'Unknown'
142+
}
143+
144+
function formatFilePath(path: string): string {
145+
const parts = path?.split('/') || []
146+
return parts.length <= 3 ? path : '.../' + parts.slice(-3).join('/')
147+
}
148+
</script>
149+
150+
<style scoped>
151+
.animate-spin { animation: spin 1s linear infinite; }
152+
@keyframes spin { from { transform: rotate(0deg); } to { transform: rotate(360deg); } }
153+
</style>

0 commit comments

Comments
 (0)