From 076526293d13379004461633d7ba4c2e83bd5ffe Mon Sep 17 00:00:00 2001 From: Bergasha Date: Sun, 28 Jun 2026 06:44:39 +1000 Subject: [PATCH] feat(docker-widget): add per-column visibility toggle (#6093) * Add 'Columns to show' label in Docker stats * feat: Add column translation keys for Docker widget * feat: Enhance table with column visibility state Added column visibility state management for the table. * Add 'noColumns' error message to en.json --- packages/translation/src/lang/en.json | 6 +++++- packages/widgets/src/docker/component.tsx | 23 +++++++++++++++++++++-- packages/widgets/src/docker/index.ts | 19 +++++++++++++++++++ 3 files changed, 45 insertions(+), 3 deletions(-) diff --git a/packages/translation/src/lang/en.json b/packages/translation/src/lang/en.json index 190a13733..b6eb826dc 100644 --- a/packages/translation/src/lang/en.json +++ b/packages/translation/src/lang/en.json @@ -2357,6 +2357,9 @@ "name": "Docker stats", "description": "Stats of your containers (This widget can only be added with administrator privileges)", "option": { + "columns": { + "label": "Columns to show" + }, "enableRowSorting": { "label": "Enable items sorting" }, @@ -5096,7 +5099,8 @@ } }, "error": { - "internalServerError": "Failed to fetch Docker containers" + "internalServerError": "Failed to fetch Docker containers", + "noColumns": "Select at least one column in the widget settings" } }, "kubernetes": { diff --git a/packages/widgets/src/docker/component.tsx b/packages/widgets/src/docker/component.tsx index d6c1d004d..a0ec57a6f 100644 --- a/packages/widgets/src/docker/component.tsx +++ b/packages/widgets/src/docker/component.tsx @@ -1,10 +1,10 @@ "use client"; import { useMemo } from "react"; -import { ActionIcon, Avatar, Badge, Group, Stack, Text, Tooltip } from "@mantine/core"; +import { ActionIcon, Avatar, Badge, Center, Group, Stack, Text, Tooltip } from "@mantine/core"; import type { IconProps } from "@tabler/icons-react"; import { IconBrandDocker, IconPlayerPlay, IconPlayerStop, IconRotateClockwise } from "@tabler/icons-react"; -import type { MRT_ColumnDef } from "mantine-react-table"; +import type { MRT_ColumnDef, MRT_VisibilityState } from "mantine-react-table"; import { MantineReactTable } from "mantine-react-table"; import type { RouterOutputs } from "@homarr/api"; @@ -213,6 +213,15 @@ export default function DockerWidget({ options, width, isEditMode }: WidgetCompo const columns = useMemo(() => createColumns(t), [t]); + const columnVisibility: MRT_VisibilityState = { + name: options.columns.includes("name"), + state: options.columns.includes("state"), + host: options.columns.includes("host"), + cpuUsage: options.columns.includes("cpuUsage"), + memoryUsage: options.columns.includes("memoryUsage"), + actions: options.columns.includes("actions"), + }; + const table = useTranslatedMantineReactTable({ columns, data: containers, @@ -233,6 +242,9 @@ export default function DockerWidget({ options, width, isEditMode }: WidgetCompo sorting: [{ id: options.defaultSort, desc: options.descendingDefaultSort }], density: "xs", }, + state: { + columnVisibility, + }, mantinePaperProps: { flex: 1, withBorder: false, @@ -260,6 +272,13 @@ export default function DockerWidget({ options, width, isEditMode }: WidgetCompo }, }); + if (options.columns.length === 0) + return ( +
+ {t("error.noColumns")} +
+ ); + return ( diff --git a/packages/widgets/src/docker/index.ts b/packages/widgets/src/docker/index.ts index 1a0964af3..76cdb97f3 100644 --- a/packages/widgets/src/docker/index.ts +++ b/packages/widgets/src/docker/index.ts @@ -12,10 +12,29 @@ const columnsList = [ "memoryUsage", ] as const satisfies (keyof RouterOutputs["docker"]["getContainers"]["containers"][number])[]; +const allColumnsList = ["name", "state", "host", "cpuUsage", "memoryUsage", "actions"] as const; + +const columnTranslationKeyMap = { + name: "docker.field.name.label", + state: "docker.field.state.label", + host: "docker.field.host.label", + cpuUsage: "docker.field.stats.cpu.label", + memoryUsage: "docker.field.stats.memory.label", + actions: "docker.action.title", +} as const satisfies Record<(typeof allColumnsList)[number], string>; + export const { definition, componentLoader } = createWidgetDefinition("dockerContainers", { icon: IconBrandDocker, createOptions() { return optionsBuilder.from((factory) => ({ + columns: factory.multiSelect({ + defaultValue: [...allColumnsList], + options: allColumnsList.map((value) => ({ + value, + label: (t) => t(columnTranslationKeyMap[value]), + })), + searchable: true, + }), enableRowSorting: factory.switch({ defaultValue: false, }),