diff --git a/data/configs/default.json b/data/configs/default.json index ba6a91144..d159270a2 100644 --- a/data/configs/default.json +++ b/data/configs/default.json @@ -18,6 +18,9 @@ }, "Date": { "enabled": false + }, + "Docker": { + "enabled": true } } } \ No newline at end of file diff --git a/data/constants.ts b/data/constants.ts index 8054f1409..ee97a57f4 100644 --- a/data/constants.ts +++ b/data/constants.ts @@ -1,2 +1,2 @@ export const REPO_URL = 'ajnart/homarr'; -export const CURRENT_VERSION = 'v0.8.0'; +export const CURRENT_VERSION = 'v0.8.1'; diff --git a/package.json b/package.json index 6ef4d50e4..d795ee97d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homarr", - "version": "0.8.0", + "version": "0.8.1", "description": "Homarr - A homepage for your server.", "repository": { "type": "git", diff --git a/src/components/AppShelf/AddAppShelfItem.tsx b/src/components/AppShelf/AddAppShelfItem.tsx index c9024d47c..20d759005 100644 --- a/src/components/AppShelf/AddAppShelfItem.tsx +++ b/src/components/AppShelf/AddAppShelfItem.tsx @@ -12,7 +12,6 @@ import { Select, Switch, Tabs, - Text, TextInput, Title, Tooltip, diff --git a/src/components/AppShelf/AppShelf.tsx b/src/components/AppShelf/AppShelf.tsx index abfed55cc..a47346830 100644 --- a/src/components/AppShelf/AppShelf.tsx +++ b/src/components/AppShelf/AppShelf.tsx @@ -178,21 +178,21 @@ const AppShelf = (props: any) => { ) : null} {downloadEnabled ? ( - - + - - - - + }} + > + + + + ) : null} diff --git a/src/components/Docker/DockerMenu.tsx b/src/components/Docker/DockerMenu.tsx deleted file mode 100644 index 6b9bdc8fe..000000000 --- a/src/components/Docker/DockerMenu.tsx +++ /dev/null @@ -1,91 +0,0 @@ -import { Menu, Text, useMantineTheme } from '@mantine/core'; -import { showNotification, updateNotification } from '@mantine/notifications'; -import { - IconCheck, - IconCodePlus, - IconPlayerPlay, - IconPlayerStop, - IconRotateClockwise, - IconX, -} from '@tabler/icons'; -import axios from 'axios'; -import Dockerode from 'dockerode'; - -function sendNotification(action: string, containerId: string, containerName: string) { - showNotification({ - id: 'load-data', - loading: true, - title: `${action}ing container ${containerName}`, - message: 'Your password is being checked...', - autoClose: false, - disallowClose: true, - }); - axios.get(`/api/docker/container/${containerId}?action=${action}`).then((res) => { - setTimeout(() => { - if (res.data.success === true) { - updateNotification({ - id: 'load-data', - title: 'Container restarted', - message: 'Your container was successfully restarted', - icon: , - autoClose: 2000, - }); - } - if (res.data.success === false) { - updateNotification({ - id: 'load-data', - color: 'red', - title: 'There was an error restarting your container.', - message: 'Your container has encountered issues while restarting.', - icon: , - autoClose: 2000, - }); - } - }, 500); - }); -} - -function restart(container: Dockerode.ContainerInfo) { - sendNotification('restart', container.Id, container.Names[0]); -} -function stop(container: Dockerode.ContainerInfo) { - console.log('stoping container', container.Id); -} -function start(container: Dockerode.ContainerInfo) { - console.log('starting container', container.Id); -} - -export default function DockerMenu(props: any) { - const { container }: { container: Dockerode.ContainerInfo } = props; - const theme = useMantineTheme(); - if (container === undefined) { - return null; - } - return ( - - Actions - } onClick={() => restart(container)}> - Restart - - {container.State === 'running' ? ( - }> - Stop - - ) : ( - }> - Start - - )} - {/* }> - Pull latest image - - }> - Logs - */} - Homarr - }> - Add to Homarr - - - ); -} diff --git a/src/components/layout/Header.tsx b/src/components/layout/Header.tsx index 3964e7a83..27fadf06e 100644 --- a/src/components/layout/Header.tsx +++ b/src/components/layout/Header.tsx @@ -19,8 +19,8 @@ import { WeatherModule, DashdotModule, } from '../modules'; +import DockerMenuButton from '../modules/docker/DockerModule'; import { ModuleWrapper } from '../modules/moduleWrapper'; -import DockerDrawer from '../Docker/DockerDrawer'; import SearchBar from '../modules/search/SearchModule'; import { SettingsMenuButton } from '../Settings/SettingsMenu'; import { Logo } from './Logo'; @@ -53,7 +53,7 @@ export function Header(props: any) { - + diff --git a/src/components/modules/dash./DashdotModule.tsx b/src/components/modules/dash./DashdotModule.tsx index 537b2a1d4..8afb5ec62 100644 --- a/src/components/modules/dash./DashdotModule.tsx +++ b/src/components/modules/dash./DashdotModule.tsx @@ -181,7 +181,7 @@ export function DashdotComponent() {

Storage:

- {(100 * totalUsed / (totalSize || 1)).toFixed(1)}%{'\n'} + {((100 * totalUsed) / (totalSize || 1)).toFixed(1)}%{'\n'} {bytePrettyPrint(totalUsed)} / {bytePrettyPrint(totalSize)}

diff --git a/src/components/Docker/ContainerActionBar.tsx b/src/components/modules/docker/ContainerActionBar.tsx similarity index 96% rename from src/components/Docker/ContainerActionBar.tsx rename to src/components/modules/docker/ContainerActionBar.tsx index b4c17dd47..8fb1ae343 100644 --- a/src/components/Docker/ContainerActionBar.tsx +++ b/src/components/modules/docker/ContainerActionBar.tsx @@ -13,9 +13,9 @@ import { } from '@tabler/icons'; import axios from 'axios'; import Dockerode from 'dockerode'; -import { tryMatchService } from '../../tools/addToHomarr'; -import { useConfig } from '../../tools/state'; -import { AddAppShelfItemForm } from '../AppShelf/AddAppShelfItem'; +import { tryMatchService } from '../../../tools/addToHomarr'; +import { useConfig } from '../../../tools/state'; +import { AddAppShelfItemForm } from '../../AppShelf/AddAppShelfItem'; function sendDockerCommand(action: string, containerId: string, containerName: string) { showNotification({ diff --git a/src/components/Docker/ContainerState.tsx b/src/components/modules/docker/ContainerState.tsx similarity index 100% rename from src/components/Docker/ContainerState.tsx rename to src/components/modules/docker/ContainerState.tsx diff --git a/src/components/Docker/DockerDrawer.tsx b/src/components/modules/docker/DockerModule.tsx similarity index 54% rename from src/components/Docker/DockerDrawer.tsx rename to src/components/modules/docker/DockerModule.tsx index 678990cbc..993182398 100644 --- a/src/components/Docker/DockerDrawer.tsx +++ b/src/components/modules/docker/DockerModule.tsx @@ -1,31 +1,58 @@ -import { ActionIcon, Drawer, Group, LoadingOverlay } from '@mantine/core'; -import { IconBrandDocker } from '@tabler/icons'; +import { ActionIcon, Drawer, Group, LoadingOverlay, Text } from '@mantine/core'; import axios from 'axios'; import { useEffect, useState } from 'react'; import Docker from 'dockerode'; +import { IconBrandDocker, IconX } from '@tabler/icons'; +import { showNotification } from '@mantine/notifications'; import ContainerActionBar from './ContainerActionBar'; import DockerTable from './DockerTable'; +import { useConfig } from '../../../tools/state'; +import { IModule } from '../modules'; -export default function DockerDrawer(props: any) { +export const DockerModule: IModule = { + title: 'Docker', + description: 'Allows you to easily manage your torrents', + icon: IconBrandDocker, + component: DockerMenuButton, +}; + +export default function DockerMenuButton(props: any) { const [opened, setOpened] = useState(false); const [containers, setContainers] = useState([]); const [selection, setSelection] = useState([]); const [visible, setVisible] = useState(false); - - function reload() { - setVisible(true); - setTimeout(() => { - axios.get('/api/docker/containers').then((res) => { - setContainers(res.data); - setSelection([]); - setVisible(false); - }); - }, 300); - } + const { config } = useConfig(); useEffect(() => { reload(); }, []); + + function reload() { + setVisible(true); + setTimeout(() => { + axios + .get('/api/docker/containers') + .then((res) => { + setContainers(res.data); + setSelection([]); + setVisible(false); + }) + .catch(() => + // Send an Error notification + showNotification({ + autoClose: 1500, + title: Docker integration failed, + color: 'red', + icon: , + message: 'Did you forget to mount the docker socket ?', + }) + ); + }, 300); + } + const exists = config.modules?.[DockerModule.title]?.enabled ?? false; + if (!exists) { + return null; + } // Check if the user has at least one container if (containers.length < 1) return null; return ( diff --git a/src/components/Docker/DockerTable.tsx b/src/components/modules/docker/DockerTable.tsx similarity index 100% rename from src/components/Docker/DockerTable.tsx rename to src/components/modules/docker/DockerTable.tsx diff --git a/src/components/modules/docker/index.ts b/src/components/modules/docker/index.ts new file mode 100644 index 000000000..8e0a617dc --- /dev/null +++ b/src/components/modules/docker/index.ts @@ -0,0 +1 @@ +export { DockerModule } from './DockerModule'; diff --git a/src/components/modules/index.ts b/src/components/modules/index.ts index 85b4b765b..d0b89acad 100644 --- a/src/components/modules/index.ts +++ b/src/components/modules/index.ts @@ -5,3 +5,4 @@ export * from './downloads'; export * from './ping'; export * from './search'; export * from './weather'; +export * from './docker'; diff --git a/src/components/modules/search/SearchModule.tsx b/src/components/modules/search/SearchModule.tsx index eae9b52ca..75a206097 100644 --- a/src/components/modules/search/SearchModule.tsx +++ b/src/components/modules/search/SearchModule.tsx @@ -1,4 +1,4 @@ -import { Kbd, createStyles, Text, Popover, Autocomplete, Tooltip } from '@mantine/core'; +import { Kbd, createStyles, Autocomplete } from '@mantine/core'; import { useDebouncedValue, useForm, useHotkeys } from '@mantine/hooks'; import { useEffect, useRef, useState } from 'react'; import { diff --git a/src/components/modules/weather/WeatherModule.tsx b/src/components/modules/weather/WeatherModule.tsx index 36393c677..913ae9f8a 100644 --- a/src/components/modules/weather/WeatherModule.tsx +++ b/src/components/modules/weather/WeatherModule.tsx @@ -157,7 +157,7 @@ export default function WeatherComponent(props: any) { }); }, [cityInput]); if (!weather.current_weather) { - return ( + return ( <> diff --git a/src/pages/api/docker/containers.tsx b/src/pages/api/docker/containers.tsx index c4d6bf95d..e2b41cdb1 100644 --- a/src/pages/api/docker/containers.tsx +++ b/src/pages/api/docker/containers.tsx @@ -2,11 +2,14 @@ import { NextApiRequest, NextApiResponse } from 'next'; import Docker from 'dockerode'; -const docker = new Docker(); - async function Get(req: NextApiRequest, res: NextApiResponse) { - const containers = await docker.listContainers({ all: true }); - return res.status(200).json(containers); + try { + const docker = new Docker(); + const containers = await docker.listContainers(); + res.status(200).json(containers); + } catch (err) { + res.status(500).json({ err }); + } } export default async (req: NextApiRequest, res: NextApiResponse) => {