mirror of
https://github.com/ajnart/homarr.git
synced 2025-11-10 23:45:48 +01:00
✨ Add possibiltiy to add widgets to dashboard
This commit is contained in:
@@ -6,6 +6,7 @@ import { useStyles } from './styles';
|
|||||||
|
|
||||||
interface GenericAvailableElementTypeProps {
|
interface GenericAvailableElementTypeProps {
|
||||||
name: string;
|
name: string;
|
||||||
|
handleAddition: () => Promise<void>;
|
||||||
description?: string;
|
description?: string;
|
||||||
image: string | TablerIcon;
|
image: string | TablerIcon;
|
||||||
disabled?: boolean;
|
disabled?: boolean;
|
||||||
@@ -16,6 +17,7 @@ export const GenericAvailableElementType = ({
|
|||||||
description,
|
description,
|
||||||
image,
|
image,
|
||||||
disabled,
|
disabled,
|
||||||
|
handleAddition,
|
||||||
}: GenericAvailableElementTypeProps) => {
|
}: GenericAvailableElementTypeProps) => {
|
||||||
const { classes } = useStyles();
|
const { classes } = useStyles();
|
||||||
|
|
||||||
@@ -39,7 +41,15 @@ export const GenericAvailableElementType = ({
|
|||||||
</Text>
|
</Text>
|
||||||
)}
|
)}
|
||||||
</Stack>
|
</Stack>
|
||||||
<Button disabled={disabled} variant="light" size="xs" mt="auto" radius="md" fullWidth>
|
<Button
|
||||||
|
disabled={disabled}
|
||||||
|
onClick={handleAddition}
|
||||||
|
variant="light"
|
||||||
|
size="xs"
|
||||||
|
mt="auto"
|
||||||
|
radius="md"
|
||||||
|
fullWidth
|
||||||
|
>
|
||||||
Add to Dashboard
|
Add to Dashboard
|
||||||
</Button>
|
</Button>
|
||||||
</Stack>
|
</Stack>
|
||||||
|
|||||||
@@ -1,14 +1,7 @@
|
|||||||
import { Grid, Text } from '@mantine/core';
|
import { Grid, Text } from '@mantine/core';
|
||||||
import {
|
|
||||||
IconArrowsUpDown,
|
|
||||||
IconCalendarTime,
|
|
||||||
IconClock,
|
|
||||||
IconCloudRain,
|
|
||||||
IconFileDownload,
|
|
||||||
} from '@tabler/icons';
|
|
||||||
import { useTranslation } from 'next-i18next';
|
import { useTranslation } from 'next-i18next';
|
||||||
|
import { useConfigContext } from '../../../../../../config/provider';
|
||||||
import widgets from '../../../../../../widgets';
|
import widgets from '../../../../../../widgets';
|
||||||
import { GenericAvailableElementType } from '../Shared/GenericElementType';
|
|
||||||
import { SelectorBackArrow } from '../Shared/SelectorBackArrow';
|
import { SelectorBackArrow } from '../Shared/SelectorBackArrow';
|
||||||
import { WidgetElementType } from './WidgetElementType';
|
import { WidgetElementType } from './WidgetElementType';
|
||||||
|
|
||||||
@@ -20,6 +13,7 @@ export const AvailableIntegrationElements = ({
|
|||||||
onClickBack,
|
onClickBack,
|
||||||
}: AvailableIntegrationElementsProps) => {
|
}: AvailableIntegrationElementsProps) => {
|
||||||
const { t } = useTranslation('layout/element-selector/selector');
|
const { t } = useTranslation('layout/element-selector/selector');
|
||||||
|
const activeWidgets = useConfigContext().config?.widgets ?? [];
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<SelectorBackArrow onClickBack={onClickBack} />
|
<SelectorBackArrow onClickBack={onClickBack} />
|
||||||
@@ -30,9 +24,11 @@ export const AvailableIntegrationElements = ({
|
|||||||
</Text>
|
</Text>
|
||||||
|
|
||||||
<Grid>
|
<Grid>
|
||||||
{Object.entries(widgets).map(([k, v]) => (
|
{Object.entries(widgets)
|
||||||
<WidgetElementType key={k} id={k} image={v.icon} />
|
.filter(([widgetId]) => !activeWidgets.some((aw) => aw.id === widgetId))
|
||||||
))}
|
.map(([k, v]) => (
|
||||||
|
<WidgetElementType key={k} id={k} image={v.icon} widget={v} />
|
||||||
|
))}
|
||||||
</Grid>
|
</Grid>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,19 +1,63 @@
|
|||||||
import { Button, Card, Center, Grid, Stack, Text } from '@mantine/core';
|
import { useModals } from '@mantine/modals';
|
||||||
import { TablerIcon } from '@tabler/icons';
|
import { TablerIcon } from '@tabler/icons';
|
||||||
import { useTranslation } from 'next-i18next';
|
import { useTranslation } from 'next-i18next';
|
||||||
import Image from 'next/image';
|
import { useConfigContext } from '../../../../../../config/provider';
|
||||||
import React, { ReactNode } from 'react';
|
import { useConfigStore } from '../../../../../../config/store';
|
||||||
import { AvailableElementTypes } from '../Overview/AvailableElementsOverview';
|
import { IWidget, IWidgetDefinition } from '../../../../../../widgets/widgets';
|
||||||
import { GenericAvailableElementType } from '../Shared/GenericElementType';
|
import { GenericAvailableElementType } from '../Shared/GenericElementType';
|
||||||
|
|
||||||
interface WidgetElementTypeProps {
|
interface WidgetElementTypeProps {
|
||||||
id: string;
|
id: string;
|
||||||
image: string | TablerIcon;
|
image: string | TablerIcon;
|
||||||
disabled?: boolean;
|
disabled?: boolean;
|
||||||
|
widget: IWidgetDefinition;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const WidgetElementType = ({ id, image, disabled }: WidgetElementTypeProps) => {
|
export const WidgetElementType = ({ id, image, disabled, widget }: WidgetElementTypeProps) => {
|
||||||
|
const { closeModal } = useModals();
|
||||||
const { t } = useTranslation(`modules/${id}`);
|
const { t } = useTranslation(`modules/${id}`);
|
||||||
|
const { name: configName, config } = useConfigContext();
|
||||||
|
const updateConfig = useConfigStore((x) => x.updateConfig);
|
||||||
|
|
||||||
|
if (!configName) return null;
|
||||||
|
|
||||||
|
const getLowestWrapper = () => {
|
||||||
|
return config?.wrappers.sort((a, b) => a.position - b.position)[0];
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleAddition = async () => {
|
||||||
|
updateConfig(configName, (prev) => ({
|
||||||
|
...prev,
|
||||||
|
widgets: [
|
||||||
|
...prev.widgets.filter((w) => w.id !== widget.id),
|
||||||
|
{
|
||||||
|
id: widget.id,
|
||||||
|
properties: Object.entries(widget.options).reduce((prev, [k, v]) => {
|
||||||
|
prev[k] = v.defaultValue;
|
||||||
|
return prev;
|
||||||
|
}, {} as IWidget<string, any>['properties']),
|
||||||
|
area: {
|
||||||
|
type: 'wrapper',
|
||||||
|
properties: {
|
||||||
|
id: getLowestWrapper()?.id ?? '',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
shape: {
|
||||||
|
location: {
|
||||||
|
x: 0,
|
||||||
|
y: 0,
|
||||||
|
},
|
||||||
|
size: {
|
||||||
|
width: widget.gridstack.minWidth,
|
||||||
|
height: widget.gridstack.minHeight,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}));
|
||||||
|
// TODO: safe to file system
|
||||||
|
closeModal('selectElement');
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<GenericAvailableElementType
|
<GenericAvailableElementType
|
||||||
@@ -21,6 +65,7 @@ export const WidgetElementType = ({ id, image, disabled }: WidgetElementTypeProp
|
|||||||
description={t('descriptor.description')}
|
description={t('descriptor.description')}
|
||||||
image={image}
|
image={image}
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
|
handleAddition={handleAddition}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user