Skip to content
Closed
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
31 changes: 2 additions & 29 deletions view/app/containers/[id]/components/ContainerDetailsLoading.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ function ContainerDetailsLoading() {
<TabsList>
<TabsTrigger value="overview">Overview</TabsTrigger>
<TabsTrigger value="logs">Logs</TabsTrigger>
<TabsTrigger value="details">Details</TabsTrigger>

</TabsList>
<TabsContent value="overview">
<Card>
Expand Down Expand Up @@ -62,34 +62,7 @@ function ContainerDetailsLoading() {
</CardContent>
</Card>
</TabsContent>
<TabsContent value="details">
<Card>
<CardContent className="pt-6">
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
<div className="space-y-4">
<div className="space-y-2">
<Skeleton className="h-4 w-32" />
<Skeleton className="h-6 w-48" />
</div>
<div className="space-y-2">
<Skeleton className="h-4 w-32" />
<Skeleton className="h-6 w-48" />
</div>
</div>
<div className="space-y-4">
<div className="space-y-2">
<Skeleton className="h-4 w-32" />
<Skeleton className="h-6 w-48" />
</div>
<div className="space-y-2">
<Skeleton className="h-4 w-32" />
<Skeleton className="h-6 w-48" />
</div>
</div>
</div>
</CardContent>
</Card>
</TabsContent>

</Tabs>
</div>
);
Expand Down
85 changes: 85 additions & 0 deletions view/app/containers/[id]/components/ContainerMetadataCard.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
import { Card, CardHeader, CardTitle, CardContent } from '@/components/ui/card';
import { Badge } from '@/components/ui/badge';
import { formatDistanceToNow } from 'date-fns';
import { Container } from '@/redux/services/container/containerApi';
import { Info } from 'lucide-react';
import React from 'react';

interface ContainerMetadataCardProps {
container: Container;
}

export function ContainerMetadataCard({ container }: ContainerMetadataCardProps) {
return (
<Card className="w-full rounded-lg shadow-md border border-gray-200">
<CardHeader>
<CardTitle className="flex items-center gap-2 text-lg">
<Info className="h-5 w-5" /> Label
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Misleading card title.

The card title "Label" doesn't accurately describe the content, which shows comprehensive container metadata including status, creation time, IDs, ports, and mounts. Consider using "Metadata" or "Container Details" instead.

Apply this diff:

       <CardHeader>
         <CardTitle className="flex items-center gap-2 text-lg">
-          <Info className="h-5 w-5" /> Label
+          <Info className="h-5 w-5" /> Container Metadata
         </CardTitle>
       </CardHeader>
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<Info className="h-5 w-5" /> Label
<CardHeader>
<CardTitle className="flex items-center gap-2 text-lg">
<Info className="h-5 w-5" /> Container Metadata
</CardTitle>
</CardHeader>
🤖 Prompt for AI Agents
In view/app/containers/[id]/components/ContainerMetadataCard.tsx around line 17,
the visible card title text currently reads "Label" which is misleading for a
card that displays full container metadata; change that text to a clearer title
such as "Container Details" (or "Metadata") by replacing the "Label" text node
with "Container Details", and if present update any accessibility attributes
(aria-label/title) or i18n keys to match the new label so the UI and assistive
tech reflect the corrected title.

</CardTitle>
</CardHeader>
<CardContent className="p-4">
<div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
{/* Status */}
<div className="flex justify-between items-center">
<span className="text-sm text-muted-foreground font-medium">Status</span>
<Badge variant={container.status === 'running' ? 'default' : 'secondary'}>
{container.status}
</Badge>
</div>

{/* Created */}
<div className="flex justify-between items-center">
<span className="text-sm text-muted-foreground font-medium">Created</span>
<span className="text-sm">
{formatDistanceToNow(new Date(container.created), { addSuffix: true })}
</span>
</div>

{/* Container ID */}
<div className="flex justify-between items-center">
<span className="text-sm text-muted-foreground font-medium">Container ID</span>
<span className="text-sm font-mono truncate">{container.id}</span>
</div>

{/* Image */}
<div className="flex justify-between items-center">
<span className="text-sm text-muted-foreground font-medium">Image</span>
<span className="text-sm font-mono truncate">{container.image}</span>
</div>

{/* Command */}
<div className="flex justify-between items-center col-span-1 sm:col-span-2">
<span className="text-sm text-muted-foreground font-medium">Command</span>
<span className="text-sm font-mono truncate">{container.command}</span>
</div>

{/* Ports */}
{container?.ports?.length > 0 && (
<div className="col-span-1 sm:col-span-2">
<span className="text-sm text-muted-foreground font-medium">Ports</span>
<div className="flex flex-wrap gap-2 mt-1">
{container.ports.map((port, index) => (
<Badge key={`${port.private_port}-${port.public_port}-${index}`} variant="outline">
{port.public_port}{port.private_port} ({port.type})
</Badge>
))}
</div>
</div>
)}

{/* Mounts */}
{container?.mounts?.length > 0 && (
<div className="col-span-1 sm:col-span-2">
<span className="text-sm text-muted-foreground font-medium">Mounts</span>
<ul className="list-disc ml-4 mt-1 text-sm font-mono">
{container.mounts.map((mount: { source: string | number | bigint | boolean | React.ReactElement<unknown, string | React.JSXElementConstructor<any>> | Iterable<React.ReactNode> | React.ReactPortal | Promise<string | number | bigint | boolean | React.ReactPortal | React.ReactElement<unknown, string | React.JSXElementConstructor<any>> | Iterable<React.ReactNode> | null | undefined> | null | undefined; destination: string | number | bigint | boolean | React.ReactElement<unknown, string | React.JSXElementConstructor<any>> | Iterable<React.ReactNode> | React.ReactPortal | Promise<string | number | bigint | boolean | React.ReactPortal | React.ReactElement<unknown, string | React.JSXElementConstructor<any>> | Iterable<React.ReactNode> | null | undefined> | null | undefined; }, idx: React.Key | null | undefined) => (
<li key={idx}>{mount.source}{mount.destination}</li>
))}
Comment on lines +75 to +77
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Replace verbose inline type with proper interface.

The inline type annotation for mounts is extremely verbose and unreadable. This should use the properly typed ContainerMount interface from the Container API definition (once fixed per the comment on containerApi.ts).

After fixing the types in containerApi.ts, this code will automatically benefit from proper typing:

-              {container.mounts.map((mount: { source: string | number | bigint | boolean | React.ReactElement<unknown, string | React.JSXElementConstructor<any>> | Iterable<React.ReactNode> | React.ReactPortal | Promise<string | number | bigint | boolean | React.ReactPortal | React.ReactElement<unknown, string | React.JSXElementConstructor<any>> | Iterable<React.ReactNode> | null | undefined> | null | undefined; destination: string | number | bigint | boolean | React.ReactElement<unknown, string | React.JSXElementConstructor<any>> | Iterable<React.ReactNode> | React.ReactPortal | Promise<string | number | bigint | boolean | React.ReactPortal | React.ReactElement<unknown, string | React.JSXElementConstructor<any>> | Iterable<React.ReactNode> | null | undefined> | null | undefined; }, idx: React.Key | null | undefined) => (
+              {container.mounts.map((mount, idx) => (
                 <li key={idx}>{mount.source} → {mount.destination}</li>
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
{container.mounts.map((mount: { source: string | number | bigint | boolean | React.ReactElement<unknown, string | React.JSXElementConstructor<any>> | Iterable<React.ReactNode> | React.ReactPortal | Promise<string | number | bigint | boolean | React.ReactPortal | React.ReactElement<unknown, string | React.JSXElementConstructor<any>> | Iterable<React.ReactNode> | null | undefined> | null | undefined; destination: string | number | bigint | boolean | React.ReactElement<unknown, string | React.JSXElementConstructor<any>> | Iterable<React.ReactNode> | React.ReactPortal | Promise<string | number | bigint | boolean | React.ReactPortal | React.ReactElement<unknown, string | React.JSXElementConstructor<any>> | Iterable<React.ReactNode> | null | undefined> | null | undefined; }, idx: React.Key | null | undefined) => (
<li key={idx}>{mount.source}{mount.destination}</li>
))}
{container.mounts.map((mount, idx) => (
<li key={idx}>{mount.source}{mount.destination}</li>
))}
🤖 Prompt for AI Agents
In view/app/containers/[id]/components/ContainerMetadataCard.tsx around lines
75-77, replace the extremely verbose inline mount type in the map callback with
the proper ContainerMount interface: remove the inline type annotation on the
map parameter, import (or reference) the ContainerMount type from the Container
API types, and rely on container.mounts being typed as ContainerMount[] (fix
containerApi.ts first if needed); ensure the map callback signature is simply
(mount, idx) => (...) and add the ContainerMount import at the top of the file
so IDE/typechecker picks up the correct types.

</ul>
</div>
)}
</div>
</CardContent>
</Card>
);
}
16 changes: 0 additions & 16 deletions view/app/containers/[id]/components/DetailsTab.tsx

This file was deleted.

6 changes: 6 additions & 0 deletions view/app/containers/[id]/components/OverviewTab.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { Card, CardHeader, CardTitle, CardContent } from '@/components/ui/card';
import { formatDistanceToNow } from 'date-fns';
import { Container } from '@/redux/services/container/containerApi';
import { useTranslation } from '@/hooks/use-translation';
import { ContainerMetadataCard } from './ContainerMetadataCard';

interface OverviewTabProps {
container: Container;
Expand Down Expand Up @@ -97,6 +98,11 @@ export function OverviewTab({ container }: OverviewTabProps) {
</div>
</CardContent>
</Card>
{/* New Metadata Card */}
<div className="col-span-1 md:col-span-2">
<ContainerMetadataCard container={container} />
</div>

</div>
);
}
14 changes: 7 additions & 7 deletions view/app/containers/[id]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ import { useRouter, useParams } from 'next/navigation';
import { useEffect, useState } from 'react';
import { OverviewTab } from './components/OverviewTab';
import { LogsTab } from './components/LogsTab';
import { DetailsTab } from './components/DetailsTab';
// import { DetailsTab } from './components/DetailsTab';
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion | 🟠 Major

Remove commented import.

Commented-out code should be deleted rather than kept in the codebase. The Details tab has been removed per PR objectives, so this import is no longer needed.

Apply this diff:

 import { LogsTab } from './components/LogsTab';
-// import { DetailsTab } from './components/DetailsTab';
 import { Terminal as TerminalComponent } from './components/Terminal';
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// import { DetailsTab } from './components/DetailsTab';
import { LogsTab } from './components/LogsTab';
import { Terminal as TerminalComponent } from './components/Terminal';
🤖 Prompt for AI Agents
In view/app/containers/[id]/page.tsx around line 28, remove the commented-out
import line "// import { DetailsTab } from './components/DetailsTab';" — delete
the commented code so the file no longer contains the unused commented import
(the Details tab was removed and the import is obsolete).

import { Terminal as TerminalComponent } from './components/Terminal';
import ContainerDetailsLoading from './components/ContainerDetailsLoading';
import { DeleteDialog } from '@/components/ui/delete-dialog';
Expand Down Expand Up @@ -170,7 +170,7 @@ export default function ContainerDetailsPage() {

<div className="space-y-4">
<Tabs defaultValue="overview" className="w-full">
<TabsList className="grid w-full grid-cols-5">
<TabsList className="grid w-full grid-cols-4">
<TabsTrigger value="overview">
<Info className="mr-2 h-4 w-4" />
{t('containers.overview')}
Expand All @@ -187,20 +187,20 @@ export default function ContainerDetailsPage() {
<Terminal className="mr-2 h-4 w-4" />
{t('containers.logs')}
</TabsTrigger>
<TabsTrigger value="details">
{/* <TabsTrigger value="details">
<HardDrive className="mr-2 h-4 w-4" />
{t('containers.details')}
</TabsTrigger>
</TabsTrigger> */}
Comment on lines +190 to +193
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion | 🟠 Major

Remove commented tab trigger and content.

Dead code should be removed, not commented out. Version control preserves the history if needed.

Apply this diff:

                 <TabsTrigger value="logs">
                   <Terminal className="mr-2 h-4 w-4" />
                   {t('containers.logs')}
                 </TabsTrigger>
-                {/* <TabsTrigger value="details">
-                  <HardDrive className="mr-2 h-4 w-4" />
-                  {t('containers.details')}
-                </TabsTrigger> */}
               </TabsList>
               </TabsContent>
-              {/* <TabsContent value="details" className="mt-4"> */}
-                {/* <DetailsTab container={container} /> */}
-              {/* </TabsContent> */}
               <TabsContent value="terminal" className="mt-4">

Also applies to: 201-203

🤖 Prompt for AI Agents
In view/app/containers/[id]/page.tsx around lines 190-193 (and also apply the
same change at 201-203), there are commented-out TabsTrigger and its related
content blocks that constitute dead code; remove these commented JSX lines
entirely rather than leaving them commented so the file contains only active
code and no commented tab trigger/content. Ensure you delete the commented
block(s) and adjust surrounding whitespace/indentation so the remaining JSX
remains valid and compiles.

</TabsList>
<TabsContent value="overview" className="mt-4">
<OverviewTab container={container} />
</TabsContent>
<TabsContent value="logs" className="mt-4">
<LogsTab container={container} logs={allLogs} onLoadMore={handleLoadMoreLogs} />
</TabsContent>
<TabsContent value="details" className="mt-4">
<DetailsTab container={container} />
</TabsContent>
{/* <TabsContent value="details" className="mt-4"> */}
{/* <DetailsTab container={container} /> */}
{/* </TabsContent> */}
<TabsContent value="terminal" className="mt-4">
{container.status === 'running' ? (
<TerminalComponent containerId={containerId} />
Expand Down
2 changes: 2 additions & 0 deletions view/redux/services/container/containerApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import { baseQueryWithReauth } from '@/redux/base-query';
import { CONTAINERURLS } from '@/redux/api-conf';

export interface Container {
labels: any;
mounts: any;
Comment on lines +6 to +7
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Replace any types with proper TypeScript interfaces.

Using any for labels and mounts eliminates type safety and can lead to runtime errors. Based on how these fields are consumed in ContainerMetadataCard (lines 75-77), proper types should be defined.

Apply this diff to add proper type definitions:

+export interface ContainerMount {
+  source: string;
+  destination: string;
+  mode?: string;
+  rw?: boolean;
+  propagation?: string;
+}
+
 export interface Container {
-  labels: any;
-  mounts: any;
+  labels: Record<string, string>;
+  mounts: ContainerMount[];
   id: string;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
labels: any;
mounts: any;
export interface ContainerMount {
source: string;
destination: string;
mode?: string;
rw?: boolean;
propagation?: string;
}
export interface Container {
labels: Record<string, string>;
mounts: ContainerMount[];
id: string;
}
🤖 Prompt for AI Agents
In view/redux/services/container/containerApi.ts around lines 6-7, the
properties labels and mounts are typed as any; replace them with concrete
TypeScript types used by ContainerMetadataCard (lines 75-77). Define labels as
Record<string, string> (or a specific interface if keys are known) and define
mounts as an array of a Mount interface (e.g., { Type: string; Source?: string;
Destination?: string; [key: string]: any } or the exact fields consumed). Add
these type/interface declarations in this file (or a shared types file), update
the container metadata interface to use labels: Record<string,string> and
mounts: Mount[], and adjust any callers if necessary to match the new types.

id: string;
name: string;
image: string;
Expand Down