Make discord integration a module

This allows for an error message if the docker integration fails to load
This commit is contained in:
Thomas "ajnart" Camlong
2022-07-21 11:43:43 +02:00
parent 715a4bd6c7
commit 00751eeca5
17 changed files with 76 additions and 133 deletions

View File

@@ -18,6 +18,9 @@
}, },
"Date": { "Date": {
"enabled": false "enabled": false
},
"Docker": {
"enabled": true
} }
} }
} }

View File

@@ -1,2 +1,2 @@
export const REPO_URL = 'ajnart/homarr'; export const REPO_URL = 'ajnart/homarr';
export const CURRENT_VERSION = 'v0.8.0'; export const CURRENT_VERSION = 'v0.8.1';

View File

@@ -1,6 +1,6 @@
{ {
"name": "homarr", "name": "homarr",
"version": "0.8.0", "version": "0.8.1",
"description": "Homarr - A homepage for your server.", "description": "Homarr - A homepage for your server.",
"repository": { "repository": {
"type": "git", "type": "git",

View File

@@ -12,7 +12,6 @@ import {
Select, Select,
Switch, Switch,
Tabs, Tabs,
Text,
TextInput, TextInput,
Title, Title,
Tooltip, Tooltip,

View File

@@ -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: <IconCheck />,
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: <IconX />,
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 (
<Menu shadow="lg" radius="md">
<Menu.Label>Actions</Menu.Label>
<Menu.Item icon={<IconRotateClockwise color="orange" />} onClick={() => restart(container)}>
<Text>Restart</Text>
</Menu.Item>
{container.State === 'running' ? (
<Menu.Item icon={<IconPlayerStop color="red" />}>
<Text>Stop</Text>
</Menu.Item>
) : (
<Menu.Item icon={<IconPlayerPlay color="green" />}>
<Text>Start</Text>
</Menu.Item>
)}
{/* <Menu.Item icon={<IconDownload color="blue" />}>
<Text>Pull latest image </Text>
</Menu.Item>
<Menu.Item icon={<IconFileText color="grey" />}>
<Text>Logs</Text>
</Menu.Item> */}
<Menu.Label>Homarr</Menu.Label>
<Menu.Item icon={<IconCodePlus color={theme.primaryColor} />}>
<Text>Add to Homarr</Text>
</Menu.Item>
</Menu>
);
}

View File

@@ -19,8 +19,8 @@ import {
WeatherModule, WeatherModule,
DashdotModule, DashdotModule,
} from '../modules'; } from '../modules';
import DockerMenuButton from '../modules/docker/DockerModule';
import { ModuleWrapper } from '../modules/moduleWrapper'; import { ModuleWrapper } from '../modules/moduleWrapper';
import DockerDrawer from '../Docker/DockerDrawer';
import SearchBar from '../modules/search/SearchModule'; import SearchBar from '../modules/search/SearchModule';
import { SettingsMenuButton } from '../Settings/SettingsMenu'; import { SettingsMenuButton } from '../Settings/SettingsMenu';
import { Logo } from './Logo'; import { Logo } from './Logo';
@@ -53,7 +53,7 @@ export function Header(props: any) {
</Box> </Box>
<Group noWrap> <Group noWrap>
<SearchBar /> <SearchBar />
<DockerDrawer /> <DockerMenuButton />
<SettingsMenuButton /> <SettingsMenuButton />
<AddItemShelfButton /> <AddItemShelfButton />
<ActionIcon className={classes.burger} variant="default" radius="md" size="xl"> <ActionIcon className={classes.burger} variant="default" radius="md" size="xl">

View File

@@ -181,7 +181,7 @@ export function DashdotComponent() {
<div className={classes.tableRow}> <div className={classes.tableRow}>
<p className={classes.tableLabel}>Storage:</p> <p className={classes.tableLabel}>Storage:</p>
<p className={classes.tableValue}> <p className={classes.tableValue}>
{(100 * totalUsed / (totalSize || 1)).toFixed(1)}%{'\n'} {((100 * totalUsed) / (totalSize || 1)).toFixed(1)}%{'\n'}
{bytePrettyPrint(totalUsed)} / {bytePrettyPrint(totalSize)} {bytePrettyPrint(totalUsed)} / {bytePrettyPrint(totalSize)}
</p> </p>
</div> </div>

View File

@@ -13,9 +13,9 @@ import {
} from '@tabler/icons'; } from '@tabler/icons';
import axios from 'axios'; import axios from 'axios';
import Dockerode from 'dockerode'; import Dockerode from 'dockerode';
import { tryMatchService } from '../../tools/addToHomarr'; import { tryMatchService } from '../../../tools/addToHomarr';
import { useConfig } from '../../tools/state'; import { useConfig } from '../../../tools/state';
import { AddAppShelfItemForm } from '../AppShelf/AddAppShelfItem'; import { AddAppShelfItemForm } from '../../AppShelf/AddAppShelfItem';
function sendDockerCommand(action: string, containerId: string, containerName: string) { function sendDockerCommand(action: string, containerId: string, containerName: string) {
showNotification({ showNotification({

View File

@@ -1,31 +1,58 @@
import { ActionIcon, Drawer, Group, LoadingOverlay } from '@mantine/core'; import { ActionIcon, Drawer, Group, LoadingOverlay, Text } from '@mantine/core';
import { IconBrandDocker } from '@tabler/icons';
import axios from 'axios'; import axios from 'axios';
import { useEffect, useState } from 'react'; import { useEffect, useState } from 'react';
import Docker from 'dockerode'; import Docker from 'dockerode';
import { IconBrandDocker, IconX } from '@tabler/icons';
import { showNotification } from '@mantine/notifications';
import ContainerActionBar from './ContainerActionBar'; import ContainerActionBar from './ContainerActionBar';
import DockerTable from './DockerTable'; 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 [opened, setOpened] = useState(false);
const [containers, setContainers] = useState<Docker.ContainerInfo[]>([]); const [containers, setContainers] = useState<Docker.ContainerInfo[]>([]);
const [selection, setSelection] = useState<Docker.ContainerInfo[]>([]); const [selection, setSelection] = useState<Docker.ContainerInfo[]>([]);
const [visible, setVisible] = useState(false); const [visible, setVisible] = useState(false);
const { config } = useConfig();
function reload() {
setVisible(true);
setTimeout(() => {
axios.get('/api/docker/containers').then((res) => {
setContainers(res.data);
setSelection([]);
setVisible(false);
});
}, 300);
}
useEffect(() => { useEffect(() => {
reload(); 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: <Text>Docker integration failed</Text>,
color: 'red',
icon: <IconX />,
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 // Check if the user has at least one container
if (containers.length < 1) return null; if (containers.length < 1) return null;
return ( return (

View File

@@ -0,0 +1 @@
export { DockerModule } from './DockerModule';

View File

@@ -5,3 +5,4 @@ export * from './downloads';
export * from './ping'; export * from './ping';
export * from './search'; export * from './search';
export * from './weather'; export * from './weather';
export * from './docker';

View File

@@ -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 { useDebouncedValue, useForm, useHotkeys } from '@mantine/hooks';
import { useEffect, useRef, useState } from 'react'; import { useEffect, useRef, useState } from 'react';
import { import {

View File

@@ -2,11 +2,14 @@ import { NextApiRequest, NextApiResponse } from 'next';
import Docker from 'dockerode'; import Docker from 'dockerode';
const docker = new Docker();
async function Get(req: NextApiRequest, res: NextApiResponse) { async function Get(req: NextApiRequest, res: NextApiResponse) {
const containers = await docker.listContainers({ all: true }); try {
return res.status(200).json(containers); 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) => { export default async (req: NextApiRequest, res: NextApiResponse) => {