Skip to content

Commit

Permalink
feat: update design (#528)
Browse files Browse the repository at this point in the history
* feat: update design

* fix: better mobile layout

* docs: update screenshot

* feat: provide icon

* refactor: separate UI steps

* test: fixup tests

* Update src/pages/index.vue

Co-authored-by: Carsten Hoffmann <[email protected]>

---------

Co-authored-by: Carsten Hoffmann <[email protected]>
  • Loading branch information
d-koppenhagen and Morl99 authored Jan 31, 2025
1 parent dc57857 commit 9b019a3
Show file tree
Hide file tree
Showing 18 changed files with 513 additions and 267 deletions.
7 changes: 5 additions & 2 deletions README.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,11 @@

Large https://github.com/aquasecurity/trivy/issues[Trivy] reports tend to become hard to grasp, that is why this project was created. It is a web application that allows to load a https://github.com/aquasecurity/trivy/issues[Trivy] report in json format and displays the vulnerabilities of a single target in an interactive data table.

.Screenshot of the application
image::overview.png[Overview of the application]
.Load a Trivy report
image::overview-0.png[Step 1: Load a Trivy report]

.Explore the vulnerabilities
image::overview-1.png[Step 2: Explore the vulnerabilities]

== Usage

Expand Down
Binary file added doc/img/overview-0.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added doc/img/overview-1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file removed doc/img/overview.png
Binary file not shown.
15 changes: 9 additions & 6 deletions e2e/home-page.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { expect, Locator, Page } from "@playwright/test"
import { expect, Locator, Page, Response } from "@playwright/test"
import * as path from "path"

export class HomePage {
Expand All @@ -8,8 +8,8 @@ export class HomePage {

constructor(page: Page) {
this.page = page
this.urlBtn = page.getByRole("button", { name: "URL" })
this.fileBtn = page.getByRole("button", { name: "File" })
this.urlBtn = page.getByRole("button", { name: "Get file from URL" })
this.fileBtn = page.getByRole("button", { name: "Upload a File" })
}

async goto(urlQueryParam?: string) {
Expand All @@ -29,10 +29,12 @@ export class HomePage {

async fetchTestFileFromUrl(url: string, waitForResponse = true) {
await this.urlBtn.click()
const fetchButton = this.page.getByRole("button", { name: "Fetch" })
const fetchButton = this.page.getByRole("button", {
name: /^Fetch$/,
})
expect(await fetchButton.isDisabled()).toBe(true)
await this.page.getByRole("textbox", { name: "Url" }).fill(url)
let responsePromise
let responsePromise: Promise<Response> | undefined
if (waitForResponse) {
responsePromise = this.page.waitForResponse(url)
}
Expand Down Expand Up @@ -87,7 +89,7 @@ export class HomePage {
}

async setSeverityFilter(severity: string) {
await this.page.getByRole("tab", { name: severity }).click()
await this.page.getByRole("button", { name: severity }).click()
}

async checkAllResults() {
Expand Down Expand Up @@ -167,6 +169,7 @@ export class HomePage {
// Check if the row exists
if ((await row.count()) > 0) {
// Check the checkbox in the first cell of the row
await this.page.waitForTimeout(300) // animation
await row.locator('input[type="checkbox"]').check({ force: true })
} else {
throw new Error(`Row with text content "${textContent}" not found`)
Expand Down
Binary file modified public/favicon.ico
Binary file not shown.
Binary file removed public/logo.png
Binary file not shown.
53 changes: 53 additions & 0 deletions public/logo_bright_bg.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
53 changes: 53 additions & 0 deletions public/logo_dark_bg.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
18 changes: 12 additions & 6 deletions src/App.vue
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@
</div>

<v-app-bar app color="primary" dark>
<template v-slot:prepend>
<img class="icon" src="/logo_dark_bg.svg" alt="" />
</template>
<v-app-bar-title>Trivy Vulnerability Explorer</v-app-bar-title>
</v-app-bar>

Expand All @@ -18,11 +21,14 @@
</v-app>
</template>

<script lang="ts" setup>
//
</script>
<script lang="ts" setup></script>

<style scoped>
img.icon {
width: 30px;
margin-left: 0.5rem;
}
#forkongithub a {
background: #000;
color: #fff;
Expand All @@ -33,7 +39,7 @@
padding: 5px 40px;
font-size: 1rem;
line-height: 2rem;
position: relative;
position: fixed;
transition: 0.5s;
}
Expand Down Expand Up @@ -61,7 +67,7 @@
@media screen and (min-width: 800px) {
#forkongithub {
position: absolute;
position: fixed;
display: block;
top: 0;
right: 0;
Expand All @@ -73,7 +79,7 @@
#forkongithub a {
width: 240px;
position: absolute;
position: fixed;
top: 50px;
right: -50px;
transform: rotate(45deg);
Expand Down
Binary file removed src/assets/logo.png
Binary file not shown.
6 changes: 0 additions & 6 deletions src/assets/logo.svg

This file was deleted.

71 changes: 24 additions & 47 deletions src/components/DataInput.vue
Original file line number Diff line number Diff line change
@@ -1,16 +1,20 @@
<template>
<v-toolbar class="mt-3" color="white" elevation="1">
<v-btn-toggle
v-model="reportSource"
mandatory
color="primary"
variant="outlined"
class="mx-3"
<v-btn-toggle
v-model="reportSource"
mandatory
rounded="pill"
color="primary"
variant="outlined"
class="mb-6"
>
<v-btn :value="ReportSource.File" prepend-icon="mdi-file-upload"
>Upload a File</v-btn
>
<v-btn :value="ReportSource.File">File</v-btn>
<v-btn :value="ReportSource.Url">URL</v-btn>
</v-btn-toggle>

<v-btn :value="ReportSource.Url" prepend-icon="mdi-link"
>Get File from URL</v-btn
>
</v-btn-toggle>
<v-container>
<v-file-upload
v-if="reportSource === ReportSource.File"
density="compact"
Expand All @@ -22,28 +26,13 @@
color="#f2f2f2"
@update:model-value="handleFileUpload($event)"
/>
</v-container>

<ReportUrlFetcher
:onNewReport="onNewReportFromUrl"
v-if="reportSource === ReportSource.Url"
:presetUrl="presetUrl"
/>

<v-autocomplete
v-model="selectedTarget"
clearable
:disabled="vulnerabilityReport.length === 0"
:items="vulnerabilityReport"
item-title="Target"
item-value="Target"
:label="
vulnerabilityReport.length === 0
? 'No targets available'
: 'Select Target'
"
hide-details
/>
</v-toolbar>
<ReportUrlFetcher
:onNewReport="onNewReportFromUrl"
v-if="reportSource === ReportSource.Url"
:presetUrl="presetUrl"
/>

<v-alert
v-if="reportError"
Expand Down Expand Up @@ -80,7 +69,6 @@ enum ReportSource {
const props = defineProps<{ presetUrl?: string }>()
const emit = defineEmits(["inputChanged"])
const selectedTarget = ref("")
const reportSource = ref(ReportSource.File)
const vulnerabilityReport = ref<VulnerabilityReportTarget[]>([])
const reportError = ref<ReportError>()
Expand All @@ -102,20 +90,9 @@ onMounted(() => {
})
const selectedVulnerabilities = computed(() => {
if (selectedTarget.value) {
return (
vulnerabilityReport.value.find((i) => i.Target === selectedTarget.value)
?.Vulnerabilities || []
)
} else {
return vulnerabilityReport.value
.filter((vr) => vr.Vulnerabilities)
.flatMap((vr) => vr.Vulnerabilities)
}
})
watch(selectedTarget, () => {
emit("inputChanged", selectedVulnerabilities.value)
return vulnerabilityReport.value
.filter((vr) => vr.Vulnerabilities)
.flatMap((vr) => vr.Vulnerabilities)
})
const parseFile = (
Expand Down
Loading

0 comments on commit 9b019a3

Please sign in to comment.