Skip to content

Commit 1edb061

Browse files
authored
Merge pull request #275 from axel7083/feature/report/containers-table
feat(report-page): containers table
2 parents 8286679 + fb4e99c commit 1edb061

File tree

11 files changed

+123
-11
lines changed

11 files changed

+123
-11
lines changed

packages/backend/src/services/alternative-service.ts

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -332,7 +332,10 @@ export class AlternativeService extends Publisher<void> implements AsyncInit, Di
332332
}
333333

334334
public async getOptimisationReport(engineId: string, imageId: string): Promise<OptimisationReport> {
335-
const imageInspectInfo = await containerEngineAPI.getImageInspect(engineId, imageId);
335+
const [imageInspectInfo, containers] = await Promise.all([
336+
containerEngineAPI.getImageInspect(engineId, imageId),
337+
containerEngineAPI.listContainers(),
338+
]);
336339

337340
const alternative = await this.findAlternative(imageInspectInfo);
338341
const sbom = await this.getSBOMReport(imageInspectInfo);
@@ -343,6 +346,14 @@ export class AlternativeService extends Publisher<void> implements AsyncInit, Di
343346
inspect: imageInspectInfo,
344347
sbom,
345348
vulnerabilities,
349+
containers: containers
350+
.filter(({ ImageID }) => ImageID === imageId)
351+
.map(container => ({
352+
engineId: container.engineId,
353+
id: container.Id,
354+
name: container.Names[0],
355+
imageID: container.ImageID,
356+
})),
346357
},
347358
alternative: alternative,
348359
};
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
<script lang="ts">
2+
import type { LocalContainer } from '@podman-desktop/extension-hummingbird-core-api';
3+
4+
interface Props {
5+
object: LocalContainer;
6+
}
7+
8+
let { object }: Props = $props();
9+
</script>
10+
11+
<div class="text-[var(--pd-table-body-text-highlight)] max-w-full overflow-hidden text-ellipsis">
12+
{object.name.startsWith('/') ? object.name.substring(1) : object.name}
13+
</div>
14+
<div class="flex flex-row text-sm gap-1">
15+
<div class="text-[var(--pd-table-body-text)]">
16+
{object.id.substring(0, 8)}
17+
</div>
18+
</div>

packages/frontend/src/routes/alternatives/(components)/columns/NameColumn.svelte

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
<script lang="ts">
22
import type { Row } from '/@/routes/alternatives/(components)/row';
3+
import LocalContainerNameColumn from '$lib/columns/LocalContainerNameColumn.svelte';
34
45
interface Props {
56
object: Row;
@@ -19,12 +20,5 @@ let { object }: Props = $props();
1920
</span>
2021
</div>
2122
{:else}
22-
<div class="text-[var(--pd-table-body-text-highlight)] max-w-full overflow-hidden text-ellipsis">
23-
{object.name.startsWith('/') ? object.name.substring(1) : object.name}
24-
</div>
25-
<div class="flex flex-row text-sm gap-1">
26-
<div class="text-[var(--pd-table-body-text)]">
27-
{object.id.substring(0, 8)}
28-
</div>
29-
</div>
23+
<LocalContainerNameColumn object={object} />
3024
{/if}

packages/frontend/src/routes/images/[engineId]/[imageId]/report/(components)/report/OptimisationReport.spec.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ test('Expect that OptimisationReport displays RawReport when alternative is pres
3232
Created: '2024-01-01T00:00:00Z',
3333
},
3434
vulnerabilities: { total: 20, critical: 2, high: 4, medium: 8, low: 6 },
35+
containers: [],
3536
},
3637
alternative: {
3738
image: {
@@ -60,6 +61,7 @@ test('Expect that OptimisationReport displays empty screen when no alternative i
6061
Created: '2024-01-01T00:00:00Z',
6162
},
6263
vulnerabilities: { total: 20 },
64+
containers: [],
6365
},
6466
alternative: undefined,
6567
};

packages/frontend/src/routes/images/[engineId]/[imageId]/report/(components)/report/RawReport.spec.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ test('Expect that RawReport displays both image cards', async () => {
4242
Created: '2024-01-01T00:00:00Z',
4343
},
4444
vulnerabilities: { total: 20, critical: 2, high: 4, medium: 8, low: 6 },
45+
containers: [],
4546
};
4647

4748
render(RawReport, {

packages/frontend/src/routes/images/[engineId]/[imageId]/report/(components)/report/RawReport.svelte

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import type { AlternativeReport, ImageReport, Tag } from '@podman-desktop/extens
66
import ReportBanner from './ReportBanner.svelte';
77
import ReportImageCard from './ReportImageCard.svelte';
88
import ReportComparison from './ReportComparison.svelte';
9+
import ClonableContainerTable from '/@/routes/images/[engineId]/[imageId]/report/(components)/table/ClonableContainerTable.svelte';
910
1011
interface Props {
1112
alternative: AlternativeReport;
@@ -43,7 +44,7 @@ const imageRepoTag = $derived(image.inspect?.RepoTags?.[0] ?? 'Unknown');
4344
const imageVersion = $derived(imageRepoTag.split(':')[1] ?? '-');
4445
</script>
4546

46-
<div class="flex flex-col gap-5 overflow-auto">
47+
<div class="flex flex-col gap-5 overflow-auto px-5">
4748
<!-- Alternate Image Found Banner -->
4849
<ReportBanner
4950
cveReductionCount={cveReduction?.count}
@@ -92,3 +93,12 @@ const imageVersion = $derived(imageRepoTag.split(':')[1] ?? '-');
9293
altSize={altSize}
9394
imageSize={image.inspect.Size} />
9495
</div>
96+
97+
<div class="px-5 pt-4">
98+
<span class="text-base font-bold text-[var(--pd-content-header)]"
99+
>Container{image.containers.length > 1 ? 's' : ''} using {image.inspect.RepoTags[0]} image</span>
100+
</div>
101+
102+
<div class="flex w-full">
103+
<ClonableContainerTable containers={image.containers} />
104+
</div>
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
<script lang="ts">
2+
import type { LocalContainer } from '@podman-desktop/extension-hummingbird-core-api/src';
3+
import { Table, TableColumn, TableRow } from '@podman-desktop/ui-svelte';
4+
import LocalContainerNameColumn from '$lib/columns/LocalContainerNameColumn.svelte';
5+
import HardenAction from '/@/routes/images/[engineId]/[imageId]/report/(components)/table/columns/HardenAction.svelte';
6+
import ContainerStatus from '/@/routes/images/[engineId]/[imageId]/report/(components)/table/columns/ContainerStatus.svelte';
7+
8+
interface Props {
9+
containers: Array<LocalContainer>;
10+
}
11+
12+
const { containers }: Props = $props();
13+
14+
const row: TableRow<LocalContainer> = new TableRow<LocalContainer>({});
15+
16+
let columns = $derived([
17+
new TableColumn<LocalContainer>('Status', {
18+
align: 'center',
19+
width: '70px',
20+
renderer: ContainerStatus,
21+
overflow: true,
22+
}),
23+
new TableColumn<LocalContainer>('Name', {
24+
width: '2fr',
25+
renderer: LocalContainerNameColumn,
26+
overflow: false,
27+
}),
28+
new TableColumn<LocalContainer>('Actions', {
29+
align: 'right',
30+
width: '250px',
31+
renderer: HardenAction,
32+
overflow: true,
33+
}),
34+
]);
35+
</script>
36+
37+
<Table kind="containers" data={containers} columns={columns} row={row} />
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<script lang="ts">
2+
import { ContainerIcon } from '@podman-desktop/ui-svelte/icons';
3+
import { StatusIcon } from '@podman-desktop/ui-svelte';
4+
import type { LocalContainer } from '@podman-desktop/extension-hummingbird-core-api/src';
5+
6+
interface Props {
7+
object: LocalContainer;
8+
}
9+
10+
let { object: _ }: Props = $props();
11+
</script>
12+
13+
<StatusIcon icon={ContainerIcon} />
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
<script lang="ts">
2+
import type { LocalContainer } from '@podman-desktop/extension-hummingbird-core-api';
3+
import { Button } from '@podman-desktop/ui-svelte';
4+
import { faHammer } from '@fortawesome/free-solid-svg-icons/faHammer';
5+
import { resolve } from '$app/paths';
6+
import { goto } from '$app/navigation';
7+
8+
interface Props {
9+
object: LocalContainer;
10+
}
11+
12+
let { object }: Props = $props();
13+
14+
function navigateToClone(): Promise<void> {
15+
return goto(
16+
resolve(`/containers/[engineId]/[id]/clone`, {
17+
engineId: object.engineId,
18+
id: object.id,
19+
}),
20+
);
21+
}
22+
</script>
23+
24+
<Button onclick={navigateToClone} icon={faHammer}>Harden with Hummingbird</Button>

packages/frontend/src/routes/images/[engineId]/[imageId]/report/+page.svelte

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ function close(): Promise<void> {
2222
{#await data.report}
2323
<span>Loading...</span>
2424
{:then report}
25-
<div class="px-5 pt-5 w-full">
25+
<div class="pt-5 w-full">
2626
<OptimisationReport object={report} />
2727
</div>
2828
{/await}

0 commit comments

Comments
 (0)