mirror of
https://github.com/ajnart/homarr.git
synced 2025-11-10 15:35:55 +01:00
🔀 merged branch dev
This commit is contained in:
@@ -10,6 +10,10 @@ import {
|
||||
} from '@tabler/icons';
|
||||
import axios from 'axios';
|
||||
import Dockerode from 'dockerode';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import { TFunction } from 'react-i18next';
|
||||
|
||||
let t: TFunction<'modules/docker', undefined>;
|
||||
|
||||
function sendDockerCommand(
|
||||
action: string,
|
||||
@@ -30,8 +34,8 @@ function sendDockerCommand(
|
||||
.then((res) => {
|
||||
updateNotification({
|
||||
id: containerId,
|
||||
title: `Container ${containerName} ${action}ed`,
|
||||
message: `Your container was successfully ${action}ed`,
|
||||
title: t('messages.successfullyExecuted.message', { containerName, action }),
|
||||
message: t('messages.successfullyExecuted.message', { action }),
|
||||
icon: <IconCheck />,
|
||||
autoClose: 2000,
|
||||
});
|
||||
@@ -40,7 +44,7 @@ function sendDockerCommand(
|
||||
updateNotification({
|
||||
id: containerId,
|
||||
color: 'red',
|
||||
title: 'There was an error',
|
||||
title: t('errors.unknownError.title'),
|
||||
message: err.response.data.reason,
|
||||
autoClose: 2000,
|
||||
});
|
||||
@@ -56,6 +60,8 @@ export interface ContainerActionBarProps {
|
||||
}
|
||||
|
||||
export default function ContainerActionBar({ selected, reload }: ContainerActionBarProps) {
|
||||
t = useTranslation('modules/docker').t;
|
||||
|
||||
return (
|
||||
<Group>
|
||||
<Button
|
||||
@@ -72,7 +78,7 @@ export default function ContainerActionBar({ selected, reload }: ContainerAction
|
||||
radius="md"
|
||||
disabled={selected.length === 0}
|
||||
>
|
||||
Restart
|
||||
{t('actionBar.restart.title')}
|
||||
</Button>
|
||||
<Button
|
||||
leftIcon={<IconPlayerStop />}
|
||||
@@ -88,7 +94,7 @@ export default function ContainerActionBar({ selected, reload }: ContainerAction
|
||||
radius="md"
|
||||
disabled={selected.length === 0}
|
||||
>
|
||||
Stop
|
||||
{t('actionBar.stop.title')}
|
||||
</Button>
|
||||
<Button
|
||||
leftIcon={<IconPlayerPlay />}
|
||||
@@ -104,10 +110,10 @@ export default function ContainerActionBar({ selected, reload }: ContainerAction
|
||||
radius="md"
|
||||
disabled={selected.length === 0}
|
||||
>
|
||||
Start
|
||||
{t('actionBar.start.title')}
|
||||
</Button>
|
||||
<Button leftIcon={<IconRefresh />} onClick={() => reload()} variant="light" color="violet" radius="md">
|
||||
Refresh data
|
||||
{t('actionBar.refreshData.title')}
|
||||
</Button>
|
||||
<Button
|
||||
leftIcon={<IconTrash />}
|
||||
@@ -123,7 +129,7 @@ export default function ContainerActionBar({ selected, reload }: ContainerAction
|
||||
}
|
||||
disabled={selected.length === 0}
|
||||
>
|
||||
Remove
|
||||
{t('actionBar.remove.title')}
|
||||
</Button>
|
||||
</Group>
|
||||
);
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { Badge, BadgeVariant, MantineSize } from '@mantine/core';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import Dockerode from 'dockerode';
|
||||
|
||||
export interface ContainerStateProps {
|
||||
@@ -7,6 +8,9 @@ export interface ContainerStateProps {
|
||||
|
||||
export default function ContainerState(props: ContainerStateProps) {
|
||||
const { state } = props;
|
||||
|
||||
const { t } = useTranslation('modules/docker');
|
||||
|
||||
const options: {
|
||||
size: MantineSize;
|
||||
radius: MantineSize;
|
||||
@@ -20,28 +24,28 @@ export default function ContainerState(props: ContainerStateProps) {
|
||||
case 'running': {
|
||||
return (
|
||||
<Badge color="green" {...options}>
|
||||
Running
|
||||
{t('table.states.running')}
|
||||
</Badge>
|
||||
);
|
||||
}
|
||||
case 'created': {
|
||||
return (
|
||||
<Badge color="cyan" {...options}>
|
||||
Created
|
||||
{t('table.states.created')}
|
||||
</Badge>
|
||||
);
|
||||
}
|
||||
case 'exited': {
|
||||
return (
|
||||
<Badge color="red" {...options}>
|
||||
Stopped
|
||||
{t('table.states.stopped')}
|
||||
</Badge>
|
||||
);
|
||||
}
|
||||
default: {
|
||||
return (
|
||||
<Badge color="purple" {...options}>
|
||||
Unknown
|
||||
{t('table.states.unknown')}
|
||||
</Badge>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -4,6 +4,8 @@ import { useEffect, useState } from 'react';
|
||||
import Docker from 'dockerode';
|
||||
import { IconBrandDocker, IconX } from '@tabler/icons';
|
||||
import { showNotification } from '@mantine/notifications';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
|
||||
import ContainerActionBar from './ContainerActionBar';
|
||||
import DockerTable from './DockerTable';
|
||||
import { useConfig } from '../../tools/state';
|
||||
@@ -11,9 +13,9 @@ import { IModule } from '../ModuleTypes';
|
||||
|
||||
export const DockerModule: IModule = {
|
||||
title: 'Docker',
|
||||
description: 'Allows you to easily manage your torrents',
|
||||
icon: IconBrandDocker,
|
||||
component: DockerMenuButton,
|
||||
id: 'docker',
|
||||
};
|
||||
|
||||
export default function DockerMenuButton(props: any) {
|
||||
@@ -21,7 +23,9 @@ export default function DockerMenuButton(props: any) {
|
||||
const [containers, setContainers] = useState<Docker.ContainerInfo[]>([]);
|
||||
const [selection, setSelection] = useState<Docker.ContainerInfo[]>([]);
|
||||
const { config } = useConfig();
|
||||
const moduleEnabled = config.modules?.[DockerModule.title]?.enabled ?? false;
|
||||
const moduleEnabled = config.modules?.[DockerModule.id]?.enabled ?? false;
|
||||
|
||||
const { t } = useTranslation('modules/docker');
|
||||
|
||||
useEffect(() => {
|
||||
reload();
|
||||
@@ -44,15 +48,15 @@ export default function DockerMenuButton(props: any) {
|
||||
// Send an Error notification
|
||||
showNotification({
|
||||
autoClose: 1500,
|
||||
title: <Text>Docker integration failed</Text>,
|
||||
title: <Text>{t('errors.integrationFailed.title')}</Text>,
|
||||
color: 'red',
|
||||
icon: <IconX />,
|
||||
message: 'Did you forget to mount the docker socket ?',
|
||||
message: t('errors.integrationFailed.message'),
|
||||
});
|
||||
});
|
||||
});
|
||||
}, 300);
|
||||
}
|
||||
const exists = config.modules?.[DockerModule.title]?.enabled ?? false;
|
||||
const exists = config.modules?.[DockerModule.id]?.enabled ?? false;
|
||||
if (!exists) {
|
||||
return null;
|
||||
}
|
||||
@@ -69,7 +73,7 @@ export default function DockerMenuButton(props: any) {
|
||||
>
|
||||
<DockerTable containers={containers} selection={selection} setSelection={setSelection} />
|
||||
</Drawer>
|
||||
<Tooltip label="Docker">
|
||||
<Tooltip label={t('actionIcon.tooltip')}>
|
||||
<ActionIcon
|
||||
variant="default"
|
||||
radius="md"
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
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 { useTranslation } from 'next-i18next';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { AddAppShelfItemForm } from '../../components/AppShelf/AddAppShelfItem';
|
||||
import { tryMatchService } from '../../tools/addToHomarr';
|
||||
@@ -30,6 +31,8 @@ export default function DockerTable({
|
||||
const [search, setSearch] = useState('');
|
||||
const [opened, setOpened] = useState<boolean>(false);
|
||||
|
||||
const { t } = useTranslation('modules/docker');
|
||||
|
||||
useEffect(() => {
|
||||
setContainers(containers);
|
||||
}, [containers]);
|
||||
@@ -86,7 +89,9 @@ export default function DockerTable({
|
||||
</Badge>
|
||||
))}
|
||||
{element.Ports.length > 3 && (
|
||||
<Badge variant="filled">{element.Ports.length - 3} more</Badge>
|
||||
<Badge variant="filled">
|
||||
{t('table.body.portCollapse', { ports: element.Ports.length - 3 })}
|
||||
</Badge>
|
||||
)}
|
||||
</Group>
|
||||
</td>
|
||||
@@ -95,7 +100,7 @@ export default function DockerTable({
|
||||
</td>
|
||||
<td>
|
||||
<Group>
|
||||
<Tooltip label="Add to Homarr">
|
||||
<Tooltip label={t('table.body.action.addToHomarr')}>
|
||||
<ActionIcon
|
||||
color="indigo"
|
||||
variant="light"
|
||||
@@ -121,16 +126,16 @@ export default function DockerTable({
|
||||
radius="md"
|
||||
opened={opened}
|
||||
onClose={() => setOpened(false)}
|
||||
title="Add service"
|
||||
title={t('actionBar.addService.title')}
|
||||
>
|
||||
<AddAppShelfItemForm
|
||||
setOpened={setOpened}
|
||||
{...tryMatchService(rowSelected)}
|
||||
message="Add service to homarr"
|
||||
message={t('actionBar.addService.message')}
|
||||
/>
|
||||
</Modal>
|
||||
<TextInput
|
||||
placeholder="Search by container or image name"
|
||||
placeholder={t('search.placeholder')}
|
||||
mt="md"
|
||||
icon={<IconSearch size={14} />}
|
||||
value={search}
|
||||
@@ -149,11 +154,11 @@ export default function DockerTable({
|
||||
disabled={usedContainers.length === 0}
|
||||
/>
|
||||
</th>
|
||||
<th>Name</th>
|
||||
<th>Image</th>
|
||||
<th>Ports</th>
|
||||
<th>State</th>
|
||||
<th>Action</th>
|
||||
<th>{t('table.header.name')}</th>
|
||||
<th>{t('table.header.image')}</th>
|
||||
<th>{t('table.header.ports')}</th>
|
||||
<th>{t('table.header.state')}</th>
|
||||
<th>{t('table.header.action')}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>{rows}</tbody>
|
||||
|
||||
Reference in New Issue
Block a user