From 9003ee6350feebf0de77609e75f8b402ec363e23 Mon Sep 17 00:00:00 2001 From: Noan Date: Tue, 23 Aug 2022 19:57:03 +0200 Subject: [PATCH 1/7] :lipstick: improve ui of DockerTable component --- src/modules/docker/ContainerActionBar.tsx | 46 +++------------------- src/modules/docker/DockerTable.tsx | 47 +++++++++++++++++++++-- src/pages/api/docker/DockerSingleton.tsx | 5 ++- 3 files changed, 53 insertions(+), 45 deletions(-) diff --git a/src/modules/docker/ContainerActionBar.tsx b/src/modules/docker/ContainerActionBar.tsx index 0ae7e2ed1..3fcfc2b9b 100644 --- a/src/modules/docker/ContainerActionBar.tsx +++ b/src/modules/docker/ContainerActionBar.tsx @@ -1,19 +1,15 @@ -import { Button, Group, Modal, Title } from '@mantine/core'; +import { Button, Group, Modal } from '@mantine/core'; import { showNotification, updateNotification } from '@mantine/notifications'; import { IconCheck, IconPlayerPlay, IconPlayerStop, - IconPlus, IconRefresh, IconRotateClockwise, IconTrash, } from '@tabler/icons'; import axios from 'axios'; import Dockerode from 'dockerode'; -import { tryMatchService } from '../../tools/addToHomarr'; -import { AddAppShelfItemForm } from '../../components/AppShelf/AddAppShelfItem'; -import { useState } from 'react'; function sendDockerCommand( action: string, @@ -60,22 +56,8 @@ export interface ContainerActionBarProps { } export default function ContainerActionBar({ selected, reload }: ContainerActionBarProps) { - const [opened, setOpened] = useState(false); return ( - setOpened(false)} - title="Add service" - > - - @@ -103,6 +86,7 @@ export default function ContainerActionBar({ selected, reload }: ContainerAction variant="light" color="red" radius="md" + disabled={selected.length === 0} > Stop @@ -118,32 +102,13 @@ export default function ContainerActionBar({ selected, reload }: ContainerAction variant="light" color="green" radius="md" + disabled={selected.length === 0} > Start - - diff --git a/src/modules/docker/DockerTable.tsx b/src/modules/docker/DockerTable.tsx index 1a6915089..67b9853b2 100644 --- a/src/modules/docker/DockerTable.tsx +++ b/src/modules/docker/DockerTable.tsx @@ -1,7 +1,9 @@ -import { Table, Checkbox, Group, Badge, createStyles, ScrollArea, TextInput } from '@mantine/core'; -import { IconSearch } from '@tabler/icons'; +import { Table, Checkbox, Group, Badge, createStyles, ScrollArea, TextInput, Button, Modal, ActionIcon, Tooltip } from '@mantine/core'; +import { IconPlus, IconSearch } from '@tabler/icons'; import Dockerode from 'dockerode'; import { useEffect, useState } from 'react'; +import { AddAppShelfItemForm } from '../../components/AppShelf/AddAppShelfItem'; +import { tryMatchService } from '../../tools/addToHomarr'; import ContainerState from './ContainerState'; const useStyles = createStyles((theme) => ({ @@ -23,8 +25,10 @@ export default function DockerTable({ selection: Dockerode.ContainerInfo[]; }) { const [usedContainers, setContainers] = useState(containers); + const [rowSelected, setRowSelected] = useState(); const { classes, cx } = useStyles(); const [search, setSearch] = useState(''); + const [opened, setOpened] = useState(false); useEffect(() => { setContainers(containers); @@ -64,7 +68,9 @@ export default function DockerTable({ /> {element.Names[0].replace('/', '')} - {element.Image} + + {element.Image} + {element.Ports.sort((a, b) => a.PrivatePort - b.PrivatePort) @@ -87,18 +93,49 @@ export default function DockerTable({ + + + + { + setRowSelected(element); + setOpened(true); + }} + > + + + + + ); }); return ( + setOpened(false)} + title="Add service" + > + + } value={search} onChange={handleSearchChange} + disabled={usedContainers.length === 0} /> @@ -106,15 +143,17 @@ export default function DockerTable({ + {rows} diff --git a/src/pages/api/docker/DockerSingleton.tsx b/src/pages/api/docker/DockerSingleton.tsx index 804444274..b388699c4 100644 --- a/src/pages/api/docker/DockerSingleton.tsx +++ b/src/pages/api/docker/DockerSingleton.tsx @@ -4,7 +4,10 @@ export default class DockerSingleton extends Docker { private static dockerInstance: DockerSingleton; private constructor() { - super(); + super({ + host: '192.168.1.56', + port: 2377, + }); } public static getInstance(): DockerSingleton { From db42474ed19a2e216b0c1ab2bf4a18011508389b Mon Sep 17 00:00:00 2001 From: Noan Date: Tue, 23 Aug 2022 20:00:46 +0200 Subject: [PATCH 2/7] :bug: fix bug where Docker containers still show on refresh if socket is unreachable --- src/modules/docker/DockerModule.tsx | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/modules/docker/DockerModule.tsx b/src/modules/docker/DockerModule.tsx index caca75306..f3cedff0b 100644 --- a/src/modules/docker/DockerModule.tsx +++ b/src/modules/docker/DockerModule.tsx @@ -1,4 +1,4 @@ -import { ActionIcon, Drawer, Group, LoadingOverlay, Text, Tooltip } from '@mantine/core'; +import { ActionIcon, Drawer, Text, Tooltip } from '@mantine/core'; import axios from 'axios'; import { useEffect, useState } from 'react'; import Docker from 'dockerode'; @@ -38,7 +38,9 @@ export default function DockerMenuButton(props: any) { setContainers(res.data); setSelection([]); }) - .catch(() => + .catch(() => { + // Remove containers from the list + setContainers([]); // Send an Error notification showNotification({ autoClose: 1500, @@ -46,8 +48,8 @@ export default function DockerMenuButton(props: any) { color: 'red', icon: , message: 'Did you forget to mount the docker socket ?', - }) - ); + }); + }); }, 300); } const exists = config.modules?.[DockerModule.title]?.enabled ?? false; From 26ce7ac895ff1441cee8c7b28eddbe26f889173c Mon Sep 17 00:00:00 2001 From: Noan Date: Tue, 23 Aug 2022 20:01:28 +0200 Subject: [PATCH 3/7] :bug: fix bug where Docker containers still show on refresh if socket is unreachable --- src/pages/api/docker/DockerSingleton.tsx | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/pages/api/docker/DockerSingleton.tsx b/src/pages/api/docker/DockerSingleton.tsx index b388699c4..804444274 100644 --- a/src/pages/api/docker/DockerSingleton.tsx +++ b/src/pages/api/docker/DockerSingleton.tsx @@ -4,10 +4,7 @@ export default class DockerSingleton extends Docker { private static dockerInstance: DockerSingleton; private constructor() { - super({ - host: '192.168.1.56', - port: 2377, - }); + super(); } public static getInstance(): DockerSingleton { From 013cf45d3db3bf783c64926de6ba4837ab6ac91d Mon Sep 17 00:00:00 2001 From: Noan Date: Sat, 27 Aug 2022 00:46:36 +0200 Subject: [PATCH 4/7] =?UTF-8?q?=F0=9F=92=84=20improve=20docker=20module=20?= =?UTF-8?q?ui?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/modules/docker/ContainerActionBar.tsx | 2 +- src/modules/docker/DockerTable.tsx | 2 +- .../api/docker/{DockerSingleton.tsx => DockerSingleton.ts} | 0 3 files changed, 2 insertions(+), 2 deletions(-) rename src/pages/api/docker/{DockerSingleton.tsx => DockerSingleton.ts} (100%) diff --git a/src/modules/docker/ContainerActionBar.tsx b/src/modules/docker/ContainerActionBar.tsx index 3fcfc2b9b..78dcf493f 100644 --- a/src/modules/docker/ContainerActionBar.tsx +++ b/src/modules/docker/ContainerActionBar.tsx @@ -1,4 +1,4 @@ -import { Button, Group, Modal } from '@mantine/core'; +import { Button, Group } from '@mantine/core'; import { showNotification, updateNotification } from '@mantine/notifications'; import { IconCheck, diff --git a/src/modules/docker/DockerTable.tsx b/src/modules/docker/DockerTable.tsx index 67b9853b2..1abea8399 100644 --- a/src/modules/docker/DockerTable.tsx +++ b/src/modules/docker/DockerTable.tsx @@ -1,4 +1,4 @@ -import { Table, Checkbox, Group, Badge, createStyles, ScrollArea, TextInput, Button, Modal, ActionIcon, Tooltip } from '@mantine/core'; +import { Table, Checkbox, Group, Badge, createStyles, ScrollArea, TextInput, Modal, ActionIcon, Tooltip } from '@mantine/core'; import { IconPlus, IconSearch } from '@tabler/icons'; import Dockerode from 'dockerode'; import { useEffect, useState } from 'react'; diff --git a/src/pages/api/docker/DockerSingleton.tsx b/src/pages/api/docker/DockerSingleton.ts similarity index 100% rename from src/pages/api/docker/DockerSingleton.tsx rename to src/pages/api/docker/DockerSingleton.ts From 4bdfcce060498095a4b21af6bb126ae0688118b1 Mon Sep 17 00:00:00 2001 From: ajnart Date: Wed, 31 Aug 2022 15:52:16 +0200 Subject: [PATCH 5/7] :pencil2: Fix locales, button order and add reload state --- next-i18next.config.js | 1 - public/locales/en/modules/docker.json | 8 ++--- src/modules/docker/ContainerActionBar.tsx | 22 +++++++++--- src/modules/docker/DockerTable.tsx | 44 ++++++++++++----------- 4 files changed, 46 insertions(+), 29 deletions(-) diff --git a/next-i18next.config.js b/next-i18next.config.js index a503cd30c..d46000123 100644 --- a/next-i18next.config.js +++ b/next-i18next.config.js @@ -1,6 +1,5 @@ module.exports = { // https://www.i18next.com/overview/configuration-options#logging - debug: process.env.NODE_ENV === 'development', i18n: { defaultLocale: 'en', locales: ['en', 'de', 'es', 'fr', 'it', 'ja', 'nl', 'ru', 'sv', 'zh'], diff --git a/public/locales/en/modules/docker.json b/public/locales/en/modules/docker.json index a4d738b61..8e8bfa590 100644 --- a/public/locales/en/modules/docker.json +++ b/public/locales/en/modules/docker.json @@ -11,7 +11,8 @@ "name": "Name", "image": "Image", "ports": "Ports", - "state": "State" + "state": "State", + "addToHomarr": "Add to homarr" }, "body": { "portCollapse": "{{ports}} more" @@ -37,9 +38,8 @@ "start": { "title": "Start" }, - "refreshData": "Refresh data", - "addToHomarr": { - "title": "Add to Homarr" + "refreshData": { + "title": "Refresh data" }, "remove": { "title": "Remove" diff --git a/src/modules/docker/ContainerActionBar.tsx b/src/modules/docker/ContainerActionBar.tsx index 392246a2c..cca2970b7 100644 --- a/src/modules/docker/ContainerActionBar.tsx +++ b/src/modules/docker/ContainerActionBar.tsx @@ -11,6 +11,7 @@ import { import axios from 'axios'; import Dockerode from 'dockerode'; import { useTranslation } from 'next-i18next'; +import { useState } from 'react'; import { TFunction } from 'react-i18next'; let t: TFunction<'modules/docker', undefined>; @@ -61,9 +62,25 @@ export interface ContainerActionBarProps { export default function ContainerActionBar({ selected, reload }: ContainerActionBarProps) { t = useTranslation('modules/docker').t; - + const [isLoading, setisLoading] = useState(false); return ( + - - + ); @@ -158,7 +162,7 @@ export default function DockerTable({ - + {rows} From 8c6e84d7a91955708c1f2ba4df706ec490c16fba Mon Sep 17 00:00:00 2001 From: ajnart Date: Fri, 2 Sep 2022 12:42:37 +0200 Subject: [PATCH 6/7] :bug: Bugfix with advanced options to add service --- src/components/AppShelf/AddAppShelfItem.tsx | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/components/AppShelf/AddAppShelfItem.tsx b/src/components/AppShelf/AddAppShelfItem.tsx index efeba042a..e3d4b8479 100644 --- a/src/components/AppShelf/AddAppShelfItem.tsx +++ b/src/components/AppShelf/AddAppShelfItem.tsx @@ -39,7 +39,7 @@ export function AddItemShelfButton(props: any) { opened={props.opened || opened} onClose={() => setOpened(false)} > - + void } & any) { - const { setOpened } = props; +export function AddAppShelfItemForm(props: { close: () => void } & any) { + const { close } = props; const { config, setConfig } = useConfig(); const [isLoading, setLoading] = useState(false); const { t } = useTranslation('layout/add-service-app-shelf'); @@ -200,7 +200,7 @@ export function AddAppShelfItemForm(props: { setOpened: (b: boolean) => void } & services: [...config.services, newForm], }); } - setOpened(false); + close(false); form.reset(); })} > @@ -393,7 +393,7 @@ export function AddAppShelfItemForm(props: { setOpened: (b: boolean) => void } & )} - + Date: Fri, 2 Sep 2022 13:01:56 +0200 Subject: [PATCH 7/7] :lipstick: Change UI for docker module --- public/locales/en/modules/docker.json | 6 ++-- src/components/AppShelf/AddAppShelfItem.tsx | 22 ++++++++---- src/modules/docker/ContainerActionBar.tsx | 37 ++++++++++++++++++++- src/modules/docker/DockerModule.tsx | 2 +- src/modules/docker/DockerTable.tsx | 32 +----------------- 5 files changed, 58 insertions(+), 41 deletions(-) diff --git a/public/locales/en/modules/docker.json b/public/locales/en/modules/docker.json index 8e8bfa590..f54db9bd9 100644 --- a/public/locales/en/modules/docker.json +++ b/public/locales/en/modules/docker.json @@ -11,8 +11,7 @@ "name": "Name", "image": "Image", "ports": "Ports", - "state": "State", - "addToHomarr": "Add to homarr" + "state": "State" }, "body": { "portCollapse": "{{ports}} more" @@ -43,6 +42,9 @@ }, "remove": { "title": "Remove" + }, + "addToHomarr": { + "title": "Add to Homarr" } }, "messages": { diff --git a/src/components/AppShelf/AddAppShelfItem.tsx b/src/components/AppShelf/AddAppShelfItem.tsx index e3d4b8479..b2f44f4ec 100644 --- a/src/components/AppShelf/AddAppShelfItem.tsx +++ b/src/components/AppShelf/AddAppShelfItem.tsx @@ -24,10 +24,11 @@ import { v4 as uuidv4 } from 'uuid'; import { useDebouncedValue } from '@mantine/hooks'; import { useTranslation } from 'next-i18next'; import { useConfig } from '../../tools/state'; -import { tryMatchPort, ServiceTypeList, StatusCodes } from '../../tools/types'; +import { tryMatchPort, ServiceTypeList, StatusCodes, Config } from '../../tools/types'; import Tip from '../layout/Tip'; export function AddItemShelfButton(props: any) { + const { config, setConfig } = useConfig(); const [opened, setOpened] = useState(false); const { t } = useTranslation('layout/add-service-app-shelf'); return ( @@ -39,7 +40,7 @@ export function AddItemShelfButton(props: any) { opened={props.opened || opened} onClose={() => setOpened(false)} > - + void } & any) { - const { close } = props; - const { config, setConfig } = useConfig(); +interface AddAppShelfItemFormProps { + setOpened: (b: boolean) => void; + config: Config; + setConfig: (config: Config) => void; + // Any other props you want to pass to the form + [key: string]: any; +} + +export function AddAppShelfItemForm(props: AddAppShelfItemFormProps) { + const { setOpened, config, setConfig } = props; + // Only get config and setConfig from useCOnfig if they are not present in props const [isLoading, setLoading] = useState(false); const { t } = useTranslation('layout/add-service-app-shelf'); @@ -195,12 +204,13 @@ export function AddAppShelfItemForm(props: { close: () => void } & any) { }), }); } else { + console.log(newForm); setConfig({ ...config, services: [...config.services, newForm], }); } - close(false); + setOpened(false); form.reset(); })} > diff --git a/src/modules/docker/ContainerActionBar.tsx b/src/modules/docker/ContainerActionBar.tsx index cca2970b7..125ccd80c 100644 --- a/src/modules/docker/ContainerActionBar.tsx +++ b/src/modules/docker/ContainerActionBar.tsx @@ -1,9 +1,12 @@ -import { Button, Group } from '@mantine/core'; +/* eslint-disable @typescript-eslint/no-non-null-assertion */ +import { Button, Group, TextInput, Title } from '@mantine/core'; +import { closeAllModals, closeModal, openModal } from '@mantine/modals'; import { showNotification, updateNotification } from '@mantine/notifications'; import { IconCheck, IconPlayerPlay, IconPlayerStop, + IconPlus, IconRefresh, IconRotateClockwise, IconTrash, @@ -13,6 +16,9 @@ import Dockerode from 'dockerode'; import { useTranslation } from 'next-i18next'; import { useState } from 'react'; import { TFunction } from 'react-i18next'; +import { AddAppShelfItemForm } from '../../components/AppShelf/AddAppShelfItem'; +import { tryMatchService } from '../../tools/addToHomarr'; +import { useConfig } from '../../tools/state'; let t: TFunction<'modules/docker', undefined>; @@ -63,6 +69,8 @@ export interface ContainerActionBarProps { export default function ContainerActionBar({ selected, reload }: ContainerActionBarProps) { t = useTranslation('modules/docker').t; const [isLoading, setisLoading] = useState(false); + const { config, setConfig } = useConfig(); + return ( + ); } diff --git a/src/modules/docker/DockerModule.tsx b/src/modules/docker/DockerModule.tsx index d895a4625..61101723e 100644 --- a/src/modules/docker/DockerModule.tsx +++ b/src/modules/docker/DockerModule.tsx @@ -53,7 +53,7 @@ export default function DockerMenuButton(props: any) { icon: , message: t('errors.integrationFailed.message'), }); - }); + }); }, 300); } const exists = config.modules?.[DockerModule.id]?.enabled ?? false; diff --git a/src/modules/docker/DockerTable.tsx b/src/modules/docker/DockerTable.tsx index 6d4d7b2c9..c8fbf9c19 100644 --- a/src/modules/docker/DockerTable.tsx +++ b/src/modules/docker/DockerTable.tsx @@ -7,9 +7,8 @@ import { ScrollArea, TextInput, Modal, - ActionIcon, } from '@mantine/core'; -import { IconPlus, IconSearch } from '@tabler/icons'; +import { IconSearch } from '@tabler/icons'; import Dockerode from 'dockerode'; import { useTranslation } from 'next-i18next'; import { useEffect, useState } from 'react'; @@ -36,10 +35,8 @@ export default function DockerTable({ selection: Dockerode.ContainerInfo[]; }) { const [usedContainers, setContainers] = useState(containers); - const [rowSelected, setRowSelected] = useState(); const { classes, cx } = useStyles(); const [search, setSearch] = useState(''); - const [opened, setOpened] = useState(false); const { t } = useTranslation('modules/docker'); @@ -106,38 +103,12 @@ export default function DockerTable({ - ); }); return ( - setOpened(false)} - title={t('actionBar.addService.title')} - > - - {t('table.header.image')} - {rows}
0} indeterminate={selection.length > 0 && selection.length !== usedContainers.length} transitionDuration={0} + disabled={usedContainers.length === 0} /> Name Image Ports StateAction
{element.Names[0].replace('/', '')} - {element.Image} - {element.Image} {element.Ports.sort((a, b) => a.PrivatePort - b.PrivatePort) @@ -99,21 +107,17 @@ export default function DockerTable({ - - - { - setRowSelected(element); - setOpened(true); - }} - > - - - - + { + setRowSelected(element); + setOpened(true); + }} + > + +
{t('table.header.image')} {t('table.header.ports')} {t('table.header.state')}{t('table.header.action')}{t('table.header.addToHomarr')}
- { - setRowSelected(element); - setOpened(true); - }} - > - - -
{t('table.header.ports')} {t('table.header.state')}{t('table.header.addToHomarr')}