Add simple image name matching

This commit is contained in:
Thomas "ajnart" Camlong
2022-07-20 14:08:56 +02:00
parent 4b92c52ea8
commit c4e01e482e
4 changed files with 66 additions and 15 deletions

View File

@@ -1,8 +1,8 @@
import { Button, Group } from '@mantine/core'; import { Button, Group, Modal, Text, Title } from '@mantine/core';
import { useBooleanToggle } from '@mantine/hooks';
import { showNotification, updateNotification } from '@mantine/notifications'; import { showNotification, updateNotification } from '@mantine/notifications';
import { import {
IconCheck, IconCheck,
IconLicense,
IconPlayerPlay, IconPlayerPlay,
IconPlayerStop, IconPlayerStop,
IconPlus, IconPlus,
@@ -13,8 +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 addToHomarr from '../../tools/addToHomarr'; import addToHomarr, { tryMatchService } from '../../tools/addToHomarr';
import { useConfig } from '../../tools/state'; import { useConfig } from '../../tools/state';
import { AddAppShelfItemForm } from '../AppShelf/AddAppShelfItem';
function sendDockerCommand(action: string, containerId: string, containerName: string) { function sendDockerCommand(action: string, containerId: string, containerName: string) {
showNotification({ showNotification({
@@ -57,8 +58,22 @@ export interface ContainerActionBarProps {
export default function ContainerActionBar({ selected, reload }: ContainerActionBarProps) { export default function ContainerActionBar({ selected, reload }: ContainerActionBarProps) {
const { config, setConfig } = useConfig(); const { config, setConfig } = useConfig();
const [opened, setOpened] = useBooleanToggle(false);
return ( return (
<Group> <Group>
<Modal
size="xl"
radius="md"
opened={opened}
onClose={() => setOpened(false)}
title="Add service"
>
<AddAppShelfItemForm
setOpened={setOpened}
{...tryMatchService(selected.at(0))}
message="Add service to homarr"
/>
</Modal>
<Button <Button
leftIcon={<IconRotateClockwise />} leftIcon={<IconRotateClockwise />}
onClick={() => onClick={() =>
@@ -79,7 +94,11 @@ export default function ContainerActionBar({ selected, reload }: ContainerAction
onClick={() => onClick={() =>
Promise.all( Promise.all(
selected.map((container) => { selected.map((container) => {
if (container.State === 'stopped' || container.State === 'created' || container.State === 'exited') { if (
container.State === 'stopped' ||
container.State === 'created' ||
container.State === 'exited'
) {
return showNotification({ return showNotification({
id: container.Id, id: container.Id,
title: `Failed to stop ${container.Names[0].substring(1)}`, title: `Failed to stop ${container.Names[0].substring(1)}`,
@@ -120,11 +139,18 @@ export default function ContainerActionBar({ selected, reload }: ContainerAction
color="indigo" color="indigo"
variant="light" variant="light"
radius="md" radius="md"
onClick={() => onClick={() => {
Promise.all(selected.map((container) => addToHomarr(container, config, setConfig))).then( if (selected.length !== 1) {
() => reload() showNotification({
) autoClose: 5000,
} title: <Title order={4}>Please only add one service at a time!</Title>,
color: 'red',
message: undefined,
});
} else {
setOpened(true);
}
}}
> >
Add to Homarr Add to Homarr
</Button> </Button>

View File

@@ -32,7 +32,7 @@ export default function DockerDrawer(props: any) {
<Drawer opened={opened} onClose={() => setOpened(false)} padding="xl" size="full"> <Drawer opened={opened} onClose={() => setOpened(false)} padding="xl" size="full">
<ContainerActionBar selected={selection} reload={reload} /> <ContainerActionBar selected={selection} reload={reload} />
<div style={{ position: 'relative' }}> <div style={{ position: 'relative' }}>
<LoadingOverlay visible={visible} /> <LoadingOverlay transitionDuration={500} visible={visible} />
<DockerTable containers={containers} selection={selection} setSelection={setSelection} /> <DockerTable containers={containers} selection={selection} setSelection={setSelection} />
</div> </div>
</Drawer> </Drawer>

View File

@@ -1,5 +1,6 @@
import { showNotification } from '@mantine/notifications';
import Dockerode from 'dockerode'; import Dockerode from 'dockerode';
import { Config } from './types'; import { Config, MatchingImages, ServiceType, ServiceTypeList } from './types';
async function MatchIcon(name: string) { async function MatchIcon(name: string) {
const res = await fetch( const res = await fetch(
@@ -10,12 +11,30 @@ async function MatchIcon(name: string) {
return res.ok ? res.url : '/favicon.svg'; return res.ok ? res.url : '/favicon.svg';
} }
function tryMatchType(imageName: string) { function tryMatchType(imageName: string): ServiceType {
// Search for a match with the Image name from the MATCH_TYPES array // Try to find imageName inside MatchingImages
console.log(`Trying to match type for: ${imageName}`);
const match = MatchingImages.find(({ image }) => imageName.includes(image));
if (match) {
return match.type;
}
return 'Other'; return 'Other';
} }
export function tryMatchService(container: Dockerode.ContainerInfo | undefined) {
if (container === undefined) return {};
const name = container.Names[0].substring(1);
return {
name,
id: container.Id,
type: tryMatchType(container.Image),
url: `${container.Ports.at(0)?.IP}:${container.Ports.at(0)?.PublicPort}`,
icon: `https://cdn.jsdelivr.net/gh/walkxhub/dashboard-icons/png/${name
.replace(/\s+/g, '-')
.toLowerCase()}.png`,
};
}
export default async function addToHomarr( export default async function addToHomarr(
container: Dockerode.ContainerInfo, container: Dockerode.ContainerInfo,
config: Config, config: Config,
@@ -29,7 +48,7 @@ export default async function addToHomarr(
name: container.Names[0].substring(1), name: container.Names[0].substring(1),
id: container.Id, id: container.Id,
type: tryMatchType(container.Image), type: tryMatchType(container.Image),
url: `${container.Ports.at(0)?.IP}:${container.Ports.at(0)?.PublicPort}`, url: `localhost:${container.Ports.at(0)?.PublicPort}`,
icon: await MatchIcon(container.Names[0].substring(1)), icon: await MatchIcon(container.Names[0].substring(1)),
}, },
], ],

View File

@@ -82,6 +82,12 @@ export type ServiceType =
| 'qBittorrent' | 'qBittorrent'
| 'Transmission'; | 'Transmission';
export const MatchingImages: { image: string; type: ServiceType }[] = [
{ image: 'lscr.io/linuxserver/radarr', type: 'Radarr' },
{ image: 'lscr.io/linuxserver/sonarr', type: 'Sonarr' },
{ image: 'lscr.io/linuxserver/qbittorrent', type: 'qBittorrent' },
];
export interface serviceItem { export interface serviceItem {
id: string; id: string;
name: string; name: string;