Skip to content

Commit

Permalink
🔀 Merge pull request #277 from MauriceNino/feature/276
Browse files Browse the repository at this point in the history
Add dash. Integration thanks to @MauriceNino !
  • Loading branch information
ajnart authored Jul 20, 2022
2 parents e56c4b6 + c313eac commit 0fdfa55
Show file tree
Hide file tree
Showing 7 changed files with 268 additions and 26 deletions.
28 changes: 15 additions & 13 deletions src/components/AppShelf/AddAppShelfItem.tsx
Original file line number Diff line number Diff line change
@@ -1,27 +1,27 @@
import {
Modal,
ActionIcon,
Anchor,
Button,
Center,
Group,
TextInput,
Image,
Button,
Select,
LoadingOverlay,
ActionIcon,
Tooltip,
Title,
Anchor,
Text,
Tabs,
Modal,
MultiSelect,
ScrollArea,
Select,
Switch,
Tabs,
Text,
TextInput,
Title,
Tooltip,
} from '@mantine/core';
import { useForm } from '@mantine/form';
import { useEffect, useState } from 'react';
import { useDebouncedValue } from '@mantine/hooks';
import { IconApps as Apps } from '@tabler/icons';
import { useEffect, useState } from 'react';
import { v4 as uuidv4 } from 'uuid';
import { useDebouncedValue } from '@mantine/hooks';
import { useConfig } from '../../tools/state';
import { ServiceTypeList, StatusCodes } from '../../tools/types';
import Tip from '../layout/Tip';
Expand Down Expand Up @@ -59,7 +59,8 @@ function MatchIcon(name: string, form: any) {
fetch(
`https://cdn.jsdelivr.net/gh/walkxhub/dashboard-icons/png/${name
.replace(/\s+/g, '-')
.toLowerCase()}.png`
.toLowerCase()
.replace(/^dash\.$/, 'dashdot')}.png`
).then((res) => {
if (res.ok) {
form.setFieldValue('icon', res.url);
Expand All @@ -85,6 +86,7 @@ function MatchPort(name: string, form: any) {
{ name: 'readarr', value: '8787' },
{ name: 'deluge', value: '8112' },
{ name: 'transmission', value: '9091' },
{ name: 'dash.', value: '3001' },
];
// Match name with portmap key
const port = portmap.find((p) => p.name === name.toLowerCase());
Expand Down
21 changes: 11 additions & 10 deletions src/components/layout/Header.tsx
Original file line number Diff line number Diff line change
@@ -1,23 +1,23 @@
import React from 'react';
import {
createStyles,
Header as Head,
Group,
ActionIcon,
Box,
Burger,
createStyles,
Drawer,
Title,
Group,
Header as Head,
ScrollArea,
ActionIcon,
Title,
Transition,
} from '@mantine/core';
import { useBooleanToggle } from '@mantine/hooks';
import { Logo } from './Logo';
import SearchBar from '../modules/search/SearchModule';
import { AddItemShelfButton } from '../AppShelf/AddAppShelfItem';
import { SettingsMenuButton } from '../Settings/SettingsMenu';
import { CalendarModule, DateModule, TotalDownloadsModule, WeatherModule } from '../modules';
import { DashdotModule } from '../modules/dash.';
import { ModuleWrapper } from '../modules/moduleWrapper';
import { CalendarModule, TotalDownloadsModule, WeatherModule, DateModule } from '../modules';
import SearchBar from '../modules/search/SearchModule';
import { SettingsMenuButton } from '../Settings/SettingsMenu';
import { Logo } from './Logo';

const HEADER_HEIGHT = 60;

Expand Down Expand Up @@ -84,6 +84,7 @@ export function Header(props: any) {
<ModuleWrapper module={TotalDownloadsModule} />
<ModuleWrapper module={WeatherModule} />
<ModuleWrapper module={DateModule} />
<ModuleWrapper module={DashdotModule} />
</Group>
</ScrollArea>
</div>
Expand Down
2 changes: 2 additions & 0 deletions src/components/layout/Widgets.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { Group } from '@mantine/core';
import { useMediaQuery } from '@mantine/hooks';
import { CalendarModule, DateModule, TotalDownloadsModule, WeatherModule } from '../modules';
import { DashdotModule } from '../modules/dash.';
import { ModuleWrapper } from '../modules/moduleWrapper';

export default function Widgets(props: any) {
Expand All @@ -14,6 +15,7 @@ export default function Widgets(props: any) {
<ModuleWrapper module={TotalDownloadsModule} />
<ModuleWrapper module={WeatherModule} />
<ModuleWrapper module={DateModule} />
<ModuleWrapper module={DashdotModule} />
</Group>
)}
</>
Expand Down
233 changes: 233 additions & 0 deletions src/components/modules/dash./DashdotModule.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,233 @@
import { createStyles, useMantineColorScheme, useMantineTheme } from '@mantine/core';
import { IconCalendar as CalendarIcon } from '@tabler/icons';
import axios from 'axios';
import { useEffect, useState } from 'react';
import { useConfig } from '../../../tools/state';
import { serviceItem } from '../../../tools/types';
import { IModule } from '../modules';

const asModule = <T extends IModule>(t: T) => t;
export const DashdotModule = asModule({
title: 'Dash.',
description: 'A module for displaying the graphs of your running Dash. instance.',
icon: CalendarIcon,
component: DashdotComponent,
options: {
cpuMultiView: {
name: 'CPU Multi-Core View',
value: false,
},
storageMultiView: {
name: 'Storage Multi-Drive View',
value: false,
},
useCompactView: {
name: 'Use Compact View',
value: false,
},
graphs: {
name: 'Graphs',
value: ['CPU', 'RAM', 'Storage', 'Network'],
options: ['CPU', 'RAM', 'Storage', 'Network', 'GPU'],
},
},
});

const useStyles = createStyles((theme, _params) => ({
heading: {
marginTop: 0,
marginBottom: 10,
},
table: {
display: 'table',
},
tableRow: {
display: 'table-row',
},
tableLabel: {
display: 'table-cell',
paddingRight: 10,
},
tableValue: {
display: 'table-cell',
whiteSpace: 'pre-wrap',
paddingBottom: 5,
},
graphsContainer: {
display: 'flex',
flexDirection: 'row',
flexWrap: 'wrap',
rowGap: 10,
columnGap: 10,
},
iframe: {
flex: '1 0 auto',
maxWidth: '100%',
height: '140px',
borderRadius: theme.radius.lg,
},
}));

const bpsPrettyPrint = (bits?: number) =>
!bits
? '-'
: bits > 1000 * 1000 * 1000
? `${(bits / 1000 / 1000 / 1000).toFixed(1)} Gb/s`
: bits > 1000 * 1000
? `${(bits / 1000 / 1000).toFixed(1)} Mb/s`
: bits > 1000
? `${(bits / 1000).toFixed(1)} Kb/s`
: `${bits.toFixed(1)} b/s`;

const bytePrettyPrint = (byte: number): string =>
byte > 1024 * 1024 * 1024
? `${(byte / 1024 / 1024 / 1024).toFixed(1)} GiB`
: byte > 1024 * 1024
? `${(byte / 1024 / 1024).toFixed(1)} MiB`
: byte > 1024
? `${(byte / 1024).toFixed(1)} KiB`
: `${byte.toFixed(1)} B`;

const useJson = (service: serviceItem | undefined, url: string) => {
const [data, setData] = useState<any | undefined>();

const doRequest = async () => {
try {
const resp = await axios.get(url, { baseURL: service?.url });

setData(resp.data);
// eslint-disable-next-line no-empty
} catch (e) {}
};

useEffect(() => {
if (service?.url) {
doRequest();
}
}, [service?.url]);

return data;
};

export function DashdotComponent() {
const { config } = useConfig();
const theme = useMantineTheme();
const { classes } = useStyles();
const { colorScheme } = useMantineColorScheme();

const dashConfig = config.modules?.[DashdotModule.title]
.options as typeof DashdotModule['options'];
const isCompact = dashConfig?.useCompactView?.value ?? false;
const dashdotService = config.services.filter((service) => service.type === 'Dash.')[0];

const enabledGraphs = dashConfig?.graphs?.value ?? ['CPU', 'RAM', 'Storage', 'Network'];
const cpuEnabled = enabledGraphs.includes('CPU');
const storageEnabled = enabledGraphs.includes('Storage');
const ramEnabled = enabledGraphs.includes('RAM');
const networkEnabled = enabledGraphs.includes('Network');
const gpuEnabled = enabledGraphs.includes('GPU');

const info = useJson(dashdotService, '/info');
const storageLoad = useJson(dashdotService, '/load/storage');

const totalUsed =
(storageLoad?.layout as any[])?.reduce((acc, curr) => (curr.load ?? 0) + acc, 0) ?? 0;
const totalSize =
(info?.storage?.layout as any[])?.reduce((acc, curr) => (curr.size ?? 0) + acc, 0) ?? 0;

const graphs = [
{
name: 'CPU',
enabled: cpuEnabled,
params: {
multiView: dashConfig?.cpuMultiView?.value ?? false,
},
},
{
name: 'Storage',
enabled: storageEnabled && !isCompact,
params: {
multiView: dashConfig?.storageMultiView?.value ?? false,
},
},
{
name: 'RAM',
enabled: ramEnabled,
},
{
name: 'Network',
enabled: networkEnabled,
spanTwo: true,
},
{
name: 'GPU',
enabled: gpuEnabled,
spanTwo: true,
},
].filter((g) => g.enabled);

return (
<div>
<h2 className={classes.heading}>Dash.</h2>

{!dashdotService ? (
<p>No dash. service found. Please add one to your Homarr dashboard.</p>
) : !info ? (
<p>Cannot acquire information from dash. - are you running the latest version?</p>
) : (
<div className={classes.graphsContainer}>
<div className={classes.table}>
{storageEnabled && isCompact && (
<div className={classes.tableRow}>
<p className={classes.tableLabel}>Storage:</p>
<p className={classes.tableValue}>
{(totalUsed / (totalSize || 1)).toFixed(1)}%{'\n'}
{bytePrettyPrint(totalUsed)} / {bytePrettyPrint(totalSize)}
</p>
</div>
)}
{networkEnabled && (
<div className={classes.tableRow}>
<p className={classes.tableLabel}>Network:</p>
<p className={classes.tableValue}>
{bpsPrettyPrint(info?.network?.speedUp)} Up{'\n'}
{bpsPrettyPrint(info?.network?.speedDown)} Down
</p>
</div>
)}
</div>

{graphs.map((graph) => (
<iframe
className={classes.iframe}
style={
isCompact
? {
width: graph.spanTwo ? '100%' : 'calc(50% - 5px)',
}
: undefined
}
key={graph.name}
title={graph.name}
src={`${
dashdotService.url
}?singleGraphMode=true&graph=${graph.name.toLowerCase()}&theme=${colorScheme}&surface=${(colorScheme ===
'dark'
? theme.colors.dark[7]
: theme.colors.gray[0]
).substring(1)}${isCompact ? '&gap=10' : '&gap=5'}&innerRadius=${theme.radius.lg}${
graph.params
? `&${Object.entries(graph.params)
.map(([key, value]) => `${key}=${value.toString()}`)
.join('&')}`
: ''
}`}
frameBorder="0"
allowTransparency
/>
))}
</div>
)}
</div>
);
}
1 change: 1 addition & 0 deletions src/components/modules/dash./index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { DashdotModule } from './DashdotModule';
7 changes: 4 additions & 3 deletions src/components/modules/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
export * from './date';
export * from './calendar';
export * from './search';
export * from './dash.';
export * from './date';
export * from './downloads';
export * from './ping';
export * from './search';
export * from './weather';
export * from './downloads';
2 changes: 2 additions & 0 deletions src/tools/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ export const Targets = [
export const ServiceTypeList = [
'Other',
'Emby',
'Dash.',
'Deluge',
'Lidarr',
'Plex',
Expand All @@ -73,6 +74,7 @@ export const ServiceTypeList = [
export type ServiceType =
| 'Other'
| 'Emby'
| 'Dash.'
| 'Deluge'
| 'Lidarr'
| 'Plex'
Expand Down

0 comments on commit 0fdfa55

Please sign in to comment.