mirror of
https://github.com/rcourtman/Pulse.git
synced 2026-10-23 20:25:56 +00:00
Refine Docker container table signals
This commit is contained in:
@@ -251,8 +251,18 @@ export const DockerContainersTable: Component<DockerNativeTableProps> = (props)
|
||||
}
|
||||
return kinds.size > 1;
|
||||
});
|
||||
const showRestartColumn = createMemo(() =>
|
||||
scopedRows().some(
|
||||
(resource) =>
|
||||
typeof resource.docker?.restartCount === 'number' && resource.docker.restartCount > 0,
|
||||
),
|
||||
);
|
||||
const visibleColumns = createMemo(() =>
|
||||
getDockerContainerVisibleColumnsForLayout(layoutMode(), showRuntimeColumn()),
|
||||
getDockerContainerVisibleColumnsForLayout(
|
||||
layoutMode(),
|
||||
showRuntimeColumn(),
|
||||
showRestartColumn(),
|
||||
),
|
||||
);
|
||||
const visibleColumnIds = createMemo(() => visibleColumns().map((column) => column.id));
|
||||
const drawerColSpan = createMemo(() => visibleColumns().length);
|
||||
@@ -335,7 +345,6 @@ export const DockerContainersTable: Component<DockerNativeTableProps> = (props)
|
||||
const indicator = mapDockerContainerStatus(resource);
|
||||
const image = () => dockerTextValue(resource.docker?.image);
|
||||
const state = () => containerState(resource);
|
||||
const health = () => dockerTextValue(resource.docker?.health);
|
||||
const runtime = () => runtimeSummary(resource);
|
||||
const host = () => dockerHostName(resource);
|
||||
const running = () => isContainerRunning(resource);
|
||||
@@ -402,16 +411,6 @@ export const DockerContainersTable: Component<DockerNativeTableProps> = (props)
|
||||
</span>
|
||||
</TableCell>
|
||||
);
|
||||
case 'health':
|
||||
return (
|
||||
<TableCell
|
||||
class={`${getPlatformTableCellClassForKind(column.kind)} text-base-content`}
|
||||
>
|
||||
<span class="block max-w-full truncate" title={health()}>
|
||||
{health()}
|
||||
</span>
|
||||
</TableCell>
|
||||
);
|
||||
case 'cpu':
|
||||
return (
|
||||
<TableCell class={getPlatformTableCellClassForKind(column.kind)}>
|
||||
|
||||
@@ -170,12 +170,12 @@ describe('Docker native tables', () => {
|
||||
expect(screen.getByText('Memory')).toBeInTheDocument();
|
||||
expect(screen.getByText('Restarts')).toBeInTheDocument();
|
||||
expect(screen.getByText('Updates')).toBeInTheDocument();
|
||||
expect(screen.queryByText('Health')).not.toBeInTheDocument();
|
||||
expect(screen.getByText('edge-web')).toBeInTheDocument();
|
||||
expect(screen.getByText('edge-01')).toBeInTheDocument();
|
||||
expect(screen.getByText('docker 27.5.1')).toBeInTheDocument();
|
||||
expect(screen.getByText('podman 5.2.1')).toBeInTheDocument();
|
||||
expect(screen.getByText('nginx:latest')).toBeInTheDocument();
|
||||
expect(screen.getAllByText('healthy').length).toBe(2);
|
||||
expect(screen.getByText('2')).toBeInTheDocument();
|
||||
expect(screen.getByText('0.0.0.0:8080->80/tcp')).toBeInTheDocument();
|
||||
expect(screen.getByText('frontend 172.18.0.2')).toBeInTheDocument();
|
||||
@@ -236,6 +236,46 @@ describe('Docker native tables', () => {
|
||||
expect(screen.queryByText('docker 27.5.1')).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('hides the Restarts column when the current containers have no restart signal', () => {
|
||||
setViewportWidth(1500);
|
||||
|
||||
renderInRouter(() => (
|
||||
<DockerContainersTable
|
||||
resources={[
|
||||
makeResource({
|
||||
id: 'container-1',
|
||||
type: 'app-container',
|
||||
name: 'edge-web',
|
||||
status: 'running',
|
||||
docker: {
|
||||
hostname: 'edge-01',
|
||||
image: 'nginx:latest',
|
||||
containerState: 'running',
|
||||
restartCount: 0,
|
||||
},
|
||||
}),
|
||||
makeResource({
|
||||
id: 'container-2',
|
||||
type: 'app-container',
|
||||
name: 'edge-cache',
|
||||
status: 'running',
|
||||
docker: {
|
||||
hostname: 'edge-02',
|
||||
image: 'redis:7.4',
|
||||
containerState: 'running',
|
||||
},
|
||||
}),
|
||||
]}
|
||||
emptyIcon={<span />}
|
||||
emptyTitle="No containers"
|
||||
emptyDescription="No containers"
|
||||
showToolbar={false}
|
||||
/>
|
||||
));
|
||||
|
||||
expect(screen.queryByText('Restarts')).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('renders actionable Docker container updates with native agent and container IDs', async () => {
|
||||
renderInRouter(() => (
|
||||
<DockerContainersTable
|
||||
|
||||
@@ -8,7 +8,7 @@ import {
|
||||
|
||||
describe('dockerContainerTableModel', () => {
|
||||
it('keeps the mobile container table on identity, state, live metrics, and update action', () => {
|
||||
const columns = getDockerContainerVisibleColumnsForLayout('mobile', true);
|
||||
const columns = getDockerContainerVisibleColumnsForLayout('mobile', true, true);
|
||||
const ids = columns.map((column) => column.id);
|
||||
|
||||
expect(ids).toEqual(['container', 'state', 'cpu', 'memory', 'updates']);
|
||||
@@ -21,14 +21,26 @@ describe('dockerContainerTableModel', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('adds host and restart signal before slower forensic fields on tablet', () => {
|
||||
it('adds host before slower forensic fields on tablet', () => {
|
||||
expect(
|
||||
getDockerContainerVisibleColumnsForLayout('tablet', true).map((column) => column.id),
|
||||
).toEqual(['container', 'host', 'state', 'cpu', 'memory', 'restarts', 'updates']);
|
||||
getDockerContainerVisibleColumnsForLayout('tablet', true, false).map((column) => column.id),
|
||||
).toEqual(['container', 'host', 'state', 'cpu', 'memory', 'updates']);
|
||||
});
|
||||
|
||||
it('adds restarts only when the current row set has restart signal to scan', () => {
|
||||
const withoutRestarts = getDockerContainerVisibleColumnsForLayout('compact', true, false).map(
|
||||
(column) => column.id,
|
||||
);
|
||||
const withRestarts = getDockerContainerVisibleColumnsForLayout('compact', true, true).map(
|
||||
(column) => column.id,
|
||||
);
|
||||
|
||||
expect(withoutRestarts).not.toContain('restarts');
|
||||
expect(withRestarts).toContain('restarts');
|
||||
});
|
||||
|
||||
it('keeps compact desktop scan-focused and hides wide forensic columns', () => {
|
||||
const columns = getDockerContainerVisibleColumnsForLayout('compact', true);
|
||||
const columns = getDockerContainerVisibleColumnsForLayout('compact', true, true);
|
||||
const ids = columns.map((column) => column.id);
|
||||
|
||||
expect(ids).toEqual([
|
||||
@@ -49,10 +61,10 @@ describe('dockerContainerTableModel', () => {
|
||||
});
|
||||
|
||||
it('shows runtime only for mixed Docker and Podman fleets', () => {
|
||||
const compactIds = getDockerContainerVisibleColumnsForLayout('compact', false).map(
|
||||
const compactIds = getDockerContainerVisibleColumnsForLayout('compact', false, true).map(
|
||||
(column) => column.id,
|
||||
);
|
||||
const wideIds = getDockerContainerVisibleColumnsForLayout('wide', false).map(
|
||||
const wideIds = getDockerContainerVisibleColumnsForLayout('wide', false, true).map(
|
||||
(column) => column.id,
|
||||
);
|
||||
|
||||
|
||||
@@ -9,7 +9,6 @@ export type DockerContainerTableColumnId =
|
||||
| 'runtime'
|
||||
| 'image'
|
||||
| 'state'
|
||||
| 'health'
|
||||
| 'cpu'
|
||||
| 'memory'
|
||||
| 'restarts'
|
||||
@@ -45,7 +44,6 @@ const DOCKER_CONTAINER_COLUMN_MIN_LAYOUT: Record<
|
||||
image: 'compact',
|
||||
runtime: 'compact',
|
||||
ports: 'compact',
|
||||
health: 'wide',
|
||||
networks: 'wide',
|
||||
mounts: 'wide',
|
||||
};
|
||||
@@ -56,7 +54,6 @@ const DOCKER_CONTAINER_COLUMNS: DockerContainerTableColumn[] = [
|
||||
{ id: 'runtime', label: 'Runtime', kind: 'text' },
|
||||
{ id: 'image', label: 'Image', kind: 'text' },
|
||||
{ id: 'state', label: 'State', kind: 'text' },
|
||||
{ id: 'health', label: 'Health', kind: 'text' },
|
||||
{ id: 'cpu', label: 'CPU', kind: 'metric-bar' },
|
||||
{ id: 'memory', label: 'Memory', kind: 'metric-bar' },
|
||||
{ id: 'restarts', label: 'Restarts', kind: 'numeric-value' },
|
||||
@@ -72,7 +69,6 @@ const DOCKER_CONTAINER_DESKTOP_WIDTHS: Record<DockerContainerTableColumnId, numb
|
||||
runtime: 7,
|
||||
image: 16,
|
||||
state: 6,
|
||||
health: 6,
|
||||
cpu: 9,
|
||||
memory: 10,
|
||||
restarts: 6,
|
||||
@@ -121,10 +117,12 @@ const formatPercentage = (value: number): string => `${Number(value.toFixed(4))}
|
||||
export const getDockerContainerVisibleColumnsForLayout = (
|
||||
layoutMode: WorkloadTableLayoutMode,
|
||||
includeRuntime: boolean,
|
||||
includeRestarts: boolean,
|
||||
): DockerContainerTableColumn[] => {
|
||||
const layoutRank = DOCKER_CONTAINER_TABLE_LAYOUT_ORDER[layoutMode];
|
||||
return DOCKER_CONTAINER_COLUMNS.filter((column) => {
|
||||
if (column.id === 'runtime' && !includeRuntime) return false;
|
||||
if (column.id === 'restarts' && !includeRestarts) return false;
|
||||
return (
|
||||
DOCKER_CONTAINER_TABLE_LAYOUT_ORDER[DOCKER_CONTAINER_COLUMN_MIN_LAYOUT[column.id]] <=
|
||||
layoutRank
|
||||
|
||||
Reference in New Issue
Block a user