Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: update design #528

Merged
merged 7 commits into from
Jan 31, 2025
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
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