Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1,402 changes: 952 additions & 450 deletions package-lock.json

Large diffs are not rendered by default.

25 changes: 13 additions & 12 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -67,37 +67,38 @@
},
"devDependencies": {
"@tailwindcss/postcss": "^4.3.0",
"@tanstack/vue-query": "^5.100.9",
"@tanstack/vue-query": "^5.100.11",
"@types/cors": "^2.8.19",
"@types/express": "^5.0.6",
"@types/node": "^25.6.2",
"@types/node": "^25.9.1",
"@types/semver": "^7.7.1",
"@vitejs/plugin-vue": "^6.0.6",
"@vitejs/plugin-vue": "^6.0.7",
"@vue/test-utils": "^2.4.10",
"@vueuse/core": "^14.3.0",
"autoprefixer": "^10.5.0",
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
"concurrently": "^9.2.1",
"eslint": "^10.3.0",
"eslint": "^10.4.0",
"eslint-plugin-vue": "^10.9.1",
"vue-eslint-parser": "^10.3.0",
"jsdom": "^29.1.1",
"lucide-vue-next": "^1.0.0",
"pinia": "^3.0.4",
"postcss": "^8.5.14",
"postcss": "^8.5.15",
"radix-vue": "^1.9.17",
"tailwind-merge": "^3.6.0",
"tailwindcss": "^4.3.0",
"tailwindcss-animate": "^1.0.7",
"esbuild": "^0.28.0",
"tsup": "^8.5.1",
"tsx": "^4.21.0",
"tsx": "^4.22.3",
"typescript": "^6.0.3",
"typescript-eslint": "^8.59.2",
"vite": "^8.0.11",
"vitest": "^4.1.5",
"typescript-eslint": "^8.59.4",
"vite": "^8.0.13",
"vitest": "^4.1.7",
"vue": "^3.5.34",
"vue-router": "^5.0.6",
"vue-tsc": "^3.2.8"
"vue-eslint-parser": "^10.4.0",
"vue-router": "^5.0.7",
"vue-tsc": "^3.3.1"
}
}
108 changes: 57 additions & 51 deletions src/client/components/audit/AuditHistory.vue
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { computed } from 'vue'
import type { AuditLogEntry } from '@shared/types'
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'
import { Badge } from '@/components/ui/badge'
import { Skeleton } from '@/components/ui/skeleton'
import { Clock, AlertTriangle, ShieldCheck } from 'lucide-vue-next'

interface Props {
Expand Down Expand Up @@ -64,16 +65,20 @@ function getSeverityColor(severity: string): 'default' | 'destructive' | 'warnin
<CardContent>
<div
v-if="isLoading"
class="text-center py-8 text-muted-foreground"
class="space-y-3"
>
Loading audit history...
<Skeleton
v-for="i in 3"
:key="i"
class="h-12 w-full"
/>
</div>

<div
v-else-if="formattedLogs.length === 0"
class="text-center py-8 text-muted-foreground"
class="text-center py-6 text-muted-foreground"
>
<ShieldCheck class="h-12 w-12 mx-auto mb-3 opacity-50" />
<ShieldCheck class="h-10 w-10 mx-auto mb-3 opacity-50" />
<p>No audit history yet</p>
<p class="text-sm">
Run your first audit to see results here
Expand All @@ -82,69 +87,70 @@ function getSeverityColor(severity: string): 'default' | 'destructive' | 'warnin

<div
v-else
class="space-y-3"
class="divide-y"
>
<div
v-for="log in formattedLogs.slice(0, 10)"
:key="log.id"
class="p-4 border rounded-lg hover:bg-muted/50 transition-colors"
class="flex items-start justify-between py-3 gap-3 first:pt-0 last:pb-0"
>
<div class="flex items-start justify-between mb-2">
<div class="space-y-1 min-w-0">
<div class="flex items-center gap-2">
<AlertTriangle
v-if="log.totalVulnerabilities > 0"
class="h-4 w-4 text-destructive"
class="h-4 w-4 text-destructive shrink-0"
/>
<ShieldCheck
v-else
class="h-4 w-4 text-green-600"
class="h-4 w-4 text-green-600 shrink-0"
/>
<span class="font-medium">
<span class="font-medium text-sm">
{{ log.totalVulnerabilities }} vulnerabilities found
</span>
</div>
<span class="text-sm text-muted-foreground">
{{ formatDate(log.timestamp) }}
</span>
</div>

<div class="flex flex-wrap gap-2 mt-2">
<Badge
v-if="log.criticalCount > 0"
:variant="getSeverityColor('critical')"
>
Critical: {{ log.criticalCount }}
</Badge>
<Badge
v-if="log.highCount > 0"
:variant="getSeverityColor('high')"
>
High: {{ log.highCount }}
</Badge>
<Badge
v-if="log.moderateCount > 0"
:variant="getSeverityColor('moderate')"
>
Moderate: {{ log.moderateCount }}
</Badge>
<Badge
v-if="log.lowCount > 0"
variant="secondary"
>
Low: {{ log.lowCount }}
</Badge>
<Badge
v-if="log.infoCount > 0"
variant="secondary"
>
Info: {{ log.infoCount }}
</Badge>
<div class="text-xs text-muted-foreground">
{{ log.metadata.totalDependencies }} dependencies · {{ log.packageManager }}
</div>
</div>

<div class="text-sm text-muted-foreground mt-2">
<span>{{ log.metadata.totalDependencies }} total dependencies</span>
<span class="mx-2">•</span>
<span>{{ log.packageManager }}</span>
<div class="flex flex-col items-end gap-1.5 shrink-0">
<span class="text-xs text-muted-foreground">{{ formatDate(log.timestamp) }}</span>
<div class="flex flex-wrap justify-end gap-1">
<Badge
v-if="log.criticalCount > 0"
:variant="getSeverityColor('critical')"
class="text-xs"
>
C: {{ log.criticalCount }}
</Badge>
<Badge
v-if="log.highCount > 0"
:variant="getSeverityColor('high')"
class="text-xs"
>
H: {{ log.highCount }}
</Badge>
<Badge
v-if="log.moderateCount > 0"
:variant="getSeverityColor('moderate')"
class="text-xs"
>
M: {{ log.moderateCount }}
</Badge>
<Badge
v-if="log.lowCount > 0"
variant="secondary"
class="text-xs"
>
L: {{ log.lowCount }}
</Badge>
<Badge
v-if="log.infoCount > 0"
variant="secondary"
class="text-xs"
>
I: {{ log.infoCount }}
</Badge>
</div>
</div>
</div>
</div>
Expand Down
103 changes: 51 additions & 52 deletions src/client/components/audit/FixHistory.vue
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { ref, computed } from 'vue'
import type { FixLogEntry } from '@shared/types'
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'
import { Badge } from '@/components/ui/badge'
import { Skeleton } from '@/components/ui/skeleton'
import { History, CheckCircle2, XCircle, Clock, Wrench, ChevronDown, ChevronRight } from 'lucide-vue-next'

const expandedLogs = ref<Set<string>>(new Set())
Expand Down Expand Up @@ -89,16 +90,20 @@ function formatOutput(output: string | undefined): string {
<CardContent>
<div
v-if="isLoading"
class="text-center py-8 text-muted-foreground"
class="space-y-3"
>
Loading fix history...
<Skeleton
v-for="i in 3"
:key="i"
class="h-12 w-full"
/>
</div>

<div
v-else-if="formattedLogs.length === 0"
class="text-center py-8 text-muted-foreground"
class="text-center py-6 text-muted-foreground"
>
<Wrench class="h-12 w-12 mx-auto mb-3 opacity-50" />
<Wrench class="h-10 w-10 mx-auto mb-3 opacity-50" />
<p>No fix history yet</p>
<p class="text-sm">
Fix vulnerabilities to see results here
Expand All @@ -107,73 +112,67 @@ function formatOutput(output: string | undefined): string {

<div
v-else
class="space-y-3"
class="divide-y"
>
<div
v-for="log in formattedLogs.slice(0, 10)"
:key="log.id"
class="p-4 border rounded-lg hover:bg-muted/50 transition-colors"
class="py-3 first:pt-0 last:pb-0"
>
<div class="flex items-start justify-between mb-2">
<div class="flex items-center gap-2">
<component
:is="getStatusIcon(log.status)"
class="h-4 w-4"
:class="{
'text-green-600': log.status === 'completed',
'text-destructive': log.status === 'failed',
'text-muted-foreground': log.status === 'pending' || log.status === 'running',
}"
/>
<span class="font-medium">
{{ log.packageName || 'All vulnerabilities' }}
</span>
<div class="flex items-start justify-between gap-3">
<div class="space-y-1 min-w-0">
<div class="flex items-center gap-2">
<component
:is="getStatusIcon(log.status)"
class="h-4 w-4 shrink-0"
:class="{
'text-green-600': log.status === 'completed',
'text-destructive': log.status === 'failed',
'text-muted-foreground': log.status === 'pending' || log.status === 'running',
}"
/>
<span class="font-medium text-sm truncate">
{{ log.packageName || 'All vulnerabilities' }}
</span>
</div>
<div class="text-xs text-muted-foreground">
{{ formatDate(log.timestamp) }}
<template v-if="log.completedAt">
· completed {{ formatDate(log.completedAt) }}
</template>
</div>
</div>
<div class="flex items-center gap-1.5 shrink-0">
<Badge
v-if="log.force"
variant="destructive"
class="text-xs"
>
forced
</Badge>
<Badge
:variant="getStatusVariant(log.status)"
class="text-xs"
>
{{ log.status }}
</Badge>
</div>
<Badge :variant="getStatusVariant(log.status)">
{{ log.status }}
</Badge>
</div>

<div class="flex flex-wrap gap-2 mt-2">
<Badge
v-if="log.force"
variant="destructive"
>
Force update
</Badge>
<Badge
v-if="log.exitCode !== undefined"
variant="outline"
>
Exit code: {{ log.exitCode }}
</Badge>
</div>

<div class="text-sm text-muted-foreground mt-2">
<span>Started: {{ formatDate(log.timestamp) }}</span>
<template v-if="log.completedAt">
<span class="mx-2">•</span>
<span>Completed: {{ formatDate(log.completedAt) }}</span>
</template>
</div>

<!-- Show details button if there's output or error -->
<div
v-if="log.output || log.error"
class="mt-3"
class="mt-2"
>
<button
class="flex items-center gap-1 text-sm text-primary hover:underline"
class="flex items-center gap-1 text-xs text-primary hover:underline"
@click="toggleExpanded(log.id)"
>
<component
:is="isExpanded(log.id) ? ChevronDown : ChevronRight"
class="h-4 w-4"
class="h-3 w-3"
/>
{{ isExpanded(log.id) ? 'Hide' : 'Show' }} details
</button>

<!-- Expanded details section -->
<div
v-if="isExpanded(log.id)"
class="mt-2 space-y-2"
Expand Down
Loading
Loading