diff --git a/public/locales/en/modules/dashdot.json b/public/locales/en/modules/dashdot.json index 93bacf733..3b628ebb3 100644 --- a/public/locales/en/modules/dashdot.json +++ b/public/locales/en/modules/dashdot.json @@ -3,7 +3,7 @@ "name": "Dash.", "description": "A module for displaying the graphs of your running Dash. instance.", "settings": { - "title": "Settings for Dash. integration", + "title": "Settings for Dash. widget", "cpuMultiView": { "label": "CPU Multi-Core View" }, @@ -21,8 +21,8 @@ } }, "remove": { - "title": "Remove Dash. integration", - "confirm": "Are you sure, that you want to remove the Dash. integration?" + "title": "Remove Dash. widget", + "confirm": "Are you sure, that you want to remove the Dash. widget?" } }, "card": { @@ -55,4 +55,4 @@ } } } -} \ No newline at end of file +} diff --git a/src/components/Dashboard/Modals/ChangePosition/ChangeIntegrationPositionModal.tsx b/src/components/Dashboard/Modals/ChangePosition/ChangeIntegrationPositionModal.tsx index 68731123b..a9dcbfcce 100644 --- a/src/components/Dashboard/Modals/ChangePosition/ChangeIntegrationPositionModal.tsx +++ b/src/components/Dashboard/Modals/ChangePosition/ChangeIntegrationPositionModal.tsx @@ -2,10 +2,10 @@ import { SelectItem } from '@mantine/core'; import { closeModal, ContextModalProps } from '@mantine/modals'; import { useConfigContext } from '../../../../config/provider'; import { useConfigStore } from '../../../../config/store'; -import { IntegrationsType } from '../../../../types/integration'; import { WidgetChangePositionModalInnerProps } from '../../Tiles/Widgets/WidgetsMenu'; import { Tiles } from '../../Tiles/tilesDefinitions'; import { ChangePositionModal } from './ChangePositionModal'; +import widgets from '../../../../widgets'; export const ChangeIntegrationPositionModal = ({ context, @@ -63,20 +63,22 @@ export const ChangeIntegrationPositionModal = ({ ); }; -const useWidthData = (integration: keyof IntegrationsType): SelectItem[] => { - const tileDefinitions = Tiles[integration]; - const offset = tileDefinitions.minWidth ?? 2; - const length = (tileDefinitions.maxWidth ?? 12) - offset; +const useWidthData = (integration: string): SelectItem[] => { + const currentWidget = widgets[integration as keyof typeof widgets]; + if (!currentWidget) return []; + const offset = currentWidget.gridstack.minWidth ?? 2; + const length = (currentWidget.gridstack.maxWidth ?? 12) - offset; return Array.from({ length }, (_, i) => i + offset).map((n) => ({ value: n.toString(), label: `${64 * n}px`, })); }; -const useHeightData = (integration: keyof IntegrationsType): SelectItem[] => { - const tileDefinitions = Tiles[integration]; - const offset = tileDefinitions.minHeight ?? 2; - const length = (tileDefinitions.maxHeight ?? 12) - offset; +const useHeightData = (integration: string): SelectItem[] => { + const currentWidget = widgets[integration as keyof typeof widgets]; + if (!currentWidget) return []; + const offset = currentWidget.gridstack.minHeight ?? 2; + const length = (currentWidget.gridstack.maxHeight ?? 12) - offset; return Array.from({ length }, (_, i) => i + offset).map((n) => ({ value: n.toString(), label: `${64 * n}px`, diff --git a/src/components/Dashboard/Tiles/Widgets/WidgetsEditModal.tsx b/src/components/Dashboard/Tiles/Widgets/WidgetsEditModal.tsx index 64708e653..980c48427 100644 --- a/src/components/Dashboard/Tiles/Widgets/WidgetsEditModal.tsx +++ b/src/components/Dashboard/Tiles/Widgets/WidgetsEditModal.tsx @@ -1,31 +1,27 @@ +import Widgets from '../../../../widgets'; import { Button, Group, MultiSelect, Stack, Switch, TextInput } from '@mantine/core'; import { ContextModalProps } from '@mantine/modals'; import { useTranslation } from 'next-i18next'; import { useState } from 'react'; import { useConfigContext } from '../../../../config/provider'; import { useConfigStore } from '../../../../config/store'; -import { DashDotGraphType, IntegrationsType } from '../../../../types/integration'; +import { IWidget } from '../../../../widgets/widgets'; -export type WidgetEditModalInnerProps< - TIntegrationKey extends keyof IntegrationsType = keyof IntegrationsType -> = { - integration: TIntegrationKey; - options: IntegrationOptions | undefined; - labels: IntegrationOptionLabels>; +export type WidgetEditModalInnerProps = { + integration: string; + options: IWidget['properties']; }; +type IntegrationOptionsValueType = IWidget['properties'][string]; + export const WidgetsEditModal = ({ context, id, innerProps, }: ContextModalProps) => { - const translationKey = integrationModuleTranslationsMap.get(innerProps.integration); - const { t } = useTranslation([translationKey ?? '', 'common']); + const { t } = useTranslation([`modules/${innerProps.integration}`, 'common']); const [moduleProperties, setModuleProperties] = useState(innerProps.options); - const items = Object.entries(moduleProperties ?? {}) as [ - keyof typeof innerProps.options, - IntegrationOptionsValueType - ][]; + const items = Object.entries(moduleProperties ?? {}) as [string, IntegrationOptionsValueType][]; const { name: configName } = useConfigContext(); const updateConfig = useConfigStore((x) => x.updateConfig); @@ -40,6 +36,14 @@ export const WidgetsEditModal = ({ }); }; + const getMutliselectData = (option: string) => { + const currentWidgetDefinition = Widgets[innerProps.integration as keyof typeof Widgets]; + if (!Widgets) return []; + + const options = currentWidgetDefinition.options as any; + return options[option]?.data ?? []; + }; + const handleSave = () => { updateConfig(configName, (prev) => ({ ...prev, @@ -63,23 +67,24 @@ export const WidgetsEditModal = ({ <> {typeof value === 'boolean' ? ( handleChange(key, ev.currentTarget.checked)} /> ) : null} {typeof value === 'string' ? ( handleChange(key, ev.currentTarget.value)} /> ) : null} {typeof value === 'object' && Array.isArray(value) ? ( handleChange(key, v as DashDotGraphType[])} + onChange={(v) => handleChange(key, v)} /> ) : null} @@ -94,29 +99,3 @@ export const WidgetsEditModal = ({ ); }; - -type PropertiesOf< - TKey extends keyof IntegrationsType, - T extends IntegrationsType[TKey] -> = T extends { properties: unknown } ? T['properties'] : {}; - -export type IntegrationOptions = PropertiesOf< - TKey, - IntegrationsType[TKey] ->; - -export type IntegrationOptionLabels = { - [key in keyof TIntegrationOptions]: string; -}; - -type IntegrationOptionsValueType = boolean | string | DashDotGraphType[]; - -export const integrationModuleTranslationsMap = new Map([ - ['calendar', 'modules/calendar'], - ['clock', 'modules/date'], - ['weather', 'modules/weather'], - ['dashDot', 'modules/dashdot'], - ['bitTorrent', 'modules/torrents-status'], - ['useNet', 'modules/usenet'], - ['torrentNetworkTraffic', 'modules/dlspeed'], -]); diff --git a/src/components/Dashboard/Tiles/Widgets/WidgetsMenu.tsx b/src/components/Dashboard/Tiles/Widgets/WidgetsMenu.tsx index ce2743edc..3f5576731 100644 --- a/src/components/Dashboard/Tiles/Widgets/WidgetsMenu.tsx +++ b/src/components/Dashboard/Tiles/Widgets/WidgetsMenu.tsx @@ -1,36 +1,23 @@ import { Title } from '@mantine/core'; import { useTranslation } from 'next-i18next'; import { openContextModalGeneric } from '../../../../tools/mantineModalManagerExtensions'; -import { IntegrationsType } from '../../../../types/integration'; -import { TileBaseType } from '../../../../types/tile'; +import { IWidget } from '../../../../widgets/widgets'; import { GenericTileMenu } from '../GenericTileMenu'; +import { WidgetEditModalInnerProps } from './WidgetsEditModal'; import { WidgetsRemoveModalInnerProps } from './WidgetsRemoveModal'; -import { - WidgetEditModalInnerProps, - integrationModuleTranslationsMap, - IntegrationOptionLabels, - IntegrationOptions, -} from './WidgetsEditModal'; export type WidgetChangePositionModalInnerProps = { - integration: keyof IntegrationsType; - module: TileBaseType; + integration: string; + module: IWidget; }; -interface WidgetsMenuProps { - integration: TIntegrationKey; - module: TileBaseType | undefined; - options: IntegrationOptions | undefined; - labels: IntegrationOptionLabels>; +interface WidgetsMenuProps { + integration: string; + module: IWidget | undefined; } -export const WidgetsMenu = ({ - integration, - options, - labels, - module, -}: WidgetsMenuProps) => { - const { t } = useTranslation(integrationModuleTranslationsMap.get(integration)); +export const WidgetsMenu = ({ integration, module }: WidgetsMenuProps) => { + const { t } = useTranslation(`modules/${integration}`); if (!module) return null; @@ -57,13 +44,12 @@ export const WidgetsMenu = ({ }; const handleEditClick = () => { - openContextModalGeneric>({ + openContextModalGeneric({ modal: 'integrationOptions', title: {t('descriptor.settings.title')}, innerProps: { integration, - options, - labels, + options: module.properties, }, }); }; @@ -73,7 +59,7 @@ export const WidgetsMenu = ({ handleClickEdit={handleEditClick} handleClickChangePosition={handleChangeSizeClick} handleClickDelete={handleDeleteClick} - displayEdit={options !== undefined} + displayEdit={module.properties !== undefined} /> ); }; diff --git a/src/components/Dashboard/Tiles/Widgets/WidgetsRemoveModal.tsx b/src/components/Dashboard/Tiles/Widgets/WidgetsRemoveModal.tsx index 899f0a2c5..7829ca8a5 100644 --- a/src/components/Dashboard/Tiles/Widgets/WidgetsRemoveModal.tsx +++ b/src/components/Dashboard/Tiles/Widgets/WidgetsRemoveModal.tsx @@ -2,11 +2,9 @@ import React from 'react'; import { Button, Group, Stack, Text } from '@mantine/core'; import { ContextModalProps } from '@mantine/modals'; import { useTranslation } from 'next-i18next'; -import { IntegrationsType } from '../../../../types/integration'; -import { integrationModuleTranslationsMap } from './WidgetsEditModal'; export type WidgetsRemoveModalInnerProps = { - integration: keyof IntegrationsType; + integration: string; }; export const WidgetsRemoveModal = ({ @@ -14,8 +12,7 @@ export const WidgetsRemoveModal = ({ id, innerProps, }: ContextModalProps) => { - const translationKey = integrationModuleTranslationsMap.get(innerProps.integration); - const { t } = useTranslation([translationKey ?? '', 'common']); + const { t } = useTranslation([`modules/${innerProps.integration}`, 'common']); const handleDeletion = () => { // TODO: remove tile context.closeModal(id); diff --git a/src/components/Dashboard/Tiles/tilesDefinitions.tsx b/src/components/Dashboard/Tiles/tilesDefinitions.tsx index b65746ea5..8fe903d52 100644 --- a/src/components/Dashboard/Tiles/tilesDefinitions.tsx +++ b/src/components/Dashboard/Tiles/tilesDefinitions.tsx @@ -1,5 +1,5 @@ import calendarDefinition from '../../../widgets/calendar/CalendarTile'; -import clockDefinition from '../../../widgets/clock/ClockTile'; +import clockDefinition from '../../../widgets/date/DateTile'; import dashDotDefinition from '../../../widgets/dashDot/DashDotTile'; import useNetDefinition from '../../../widgets/useNet/UseNetTile'; import weatherDefinition from '../../../widgets/weather/WeatherTile'; diff --git a/src/pages/api/modules/dashdot/info.ts b/src/pages/api/modules/dashdot/info.ts index c4d03bd3f..7712a5337 100644 --- a/src/pages/api/modules/dashdot/info.ts +++ b/src/pages/api/modules/dashdot/info.ts @@ -13,7 +13,7 @@ async function Get(req: NextApiRequest, res: NextApiResponse) { const config = getConfig(configName); - const dashDotUrl = config.integrations.dashDot?.properties.url; + const dashDotUrl = config.integrations.dashdot?.properties.url; if (!dashDotUrl) { return res.status(400).json({ diff --git a/src/pages/api/modules/dashdot/storage.ts b/src/pages/api/modules/dashdot/storage.ts index a74965900..5c25299b6 100644 --- a/src/pages/api/modules/dashdot/storage.ts +++ b/src/pages/api/modules/dashdot/storage.ts @@ -13,7 +13,7 @@ async function Get(req: NextApiRequest, res: NextApiResponse) { const config = getConfig(configName); - const dashDotUrl = config.integrations.dashDot?.properties.url; + const dashDotUrl = config.integrations.dashdot?.properties.url; if (!dashDotUrl) { return res.status(400).json({ diff --git a/src/widgets/bitTorrent/BitTorrentTile.tsx b/src/widgets/bitTorrent/BitTorrentTile.tsx index 5888718bc..b61f2b987 100644 --- a/src/widgets/bitTorrent/BitTorrentTile.tsx +++ b/src/widgets/bitTorrent/BitTorrentTile.tsx @@ -5,7 +5,7 @@ import { defineWidget } from '../helper'; import { IWidget } from '../widgets'; const definition = defineWidget({ - id: 'bitTorrent', + id: 'torrents-status', icon: IconClock, options: {}, gridstack: { diff --git a/src/widgets/dashDot/DashDotTile.tsx b/src/widgets/dashDot/DashDotTile.tsx index 1688a4d9e..58ab8630d 100644 --- a/src/widgets/dashDot/DashDotTile.tsx +++ b/src/widgets/dashDot/DashDotTile.tsx @@ -13,7 +13,7 @@ import { DashDotCompactStorage } from './DashDotCompactStorage'; import { DashDotGraph } from './DashDotGraph'; const definition = defineWidget({ - id: 'dashDot', + id: 'dashdot', icon: 'https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons/png/dashdot.png', options: { cpuMultiView: { @@ -78,18 +78,7 @@ function DashDotTile({ module, className }: DashDotTileProps) { const menu = ( // TODO: add widgetWrapper that is generic and uses the definition - - module={module} - integration="dashDot" - options={module?.properties} - labels={{ - isCpuMultiView: 'descriptor.settings.cpuMultiView.label', - isStorageMultiView: 'descriptor.settings.storageMultiView.label', - isCompactView: 'descriptor.settings.useCompactView.label', - graphs: 'descriptor.settings.graphs.label', - url: 'descriptor.settings.url.label', - }} - /> + ); if (!dashDotUrl) { diff --git a/src/widgets/clock/ClockTile.tsx b/src/widgets/date/DateTile.tsx similarity index 82% rename from src/widgets/clock/ClockTile.tsx rename to src/widgets/date/DateTile.tsx index 56f6b2e3c..a36c1cc89 100644 --- a/src/widgets/clock/ClockTile.tsx +++ b/src/widgets/date/DateTile.tsx @@ -10,7 +10,7 @@ import { IWidget } from '../widgets'; import { IconClock } from '@tabler/icons'; const definition = defineWidget({ - id: 'clock', + id: 'date', icon: IconClock, options: { display24HourFormat: { @@ -18,35 +18,29 @@ const definition = defineWidget({ defaultValue: false, }, }, - gridstack: { minWidth: 4, minHeight: 2, maxWidth: 12, maxHeight: 12, }, - component: ClockTile, + component: DateTile, }); -export type IClockWidget = IWidget; +export type IDateWidget = IWidget; -interface ClockTileProps extends BaseTileProps { - module: IClockWidget; // TODO: change to new type defined through widgetDefinition +interface DateTileProps extends BaseTileProps { + module: IDateWidget; // TODO: change to new type defined through widgetDefinition } -function ClockTile({ className, module }: ClockTileProps) { +function DateTile({ className, module }: DateTileProps) { const date = useDateState(); const formatString = module.properties.display24HourFormat ? 'HH:mm' : 'h:mm A'; // TODO: add widgetWrapper that is generic and uses the definition return ( - - integration="clock" - module={module} - options={module.properties} - labels={{ is24HoursFormat: 'descriptor.settings.display24HourFormat.label' }} - /> +
{dayjs(date).format(formatString)} diff --git a/src/widgets/index.ts b/src/widgets/index.ts index 0722ed138..935cecb11 100644 --- a/src/widgets/index.ts +++ b/src/widgets/index.ts @@ -1,8 +1,16 @@ +import date from './date/DateTile'; import calendar from './calendar/CalendarTile'; -import dashDot from './dashDot/DashDotTile'; -import useNet from './useNet/UseNetTile'; -import clock from './clock/ClockTile'; +import dashdot from './dashDot/DashDotTile'; +import usenet from './useNet/UseNetTile'; import weather from './weather/WeatherTile'; import bitTorrent from './bitTorrent/BitTorrentTile'; import torrentNetworkTraffic from './torrentNetworkTraffic/TorrentNetworkTrafficTile'; -export default { calendar, dashDot, useNet, clock, weather, bitTorrent, torrentNetworkTraffic }; +export default { + calendar, + dashdot, + usenet, + weather, + 'torrents-status': bitTorrent, + dlspeed: torrentNetworkTraffic, + date, +}; diff --git a/src/widgets/torrentNetworkTraffic/TorrentNetworkTrafficTile.tsx b/src/widgets/torrentNetworkTraffic/TorrentNetworkTrafficTile.tsx index 856b4a8d1..8495076e8 100644 --- a/src/widgets/torrentNetworkTraffic/TorrentNetworkTrafficTile.tsx +++ b/src/widgets/torrentNetworkTraffic/TorrentNetworkTrafficTile.tsx @@ -5,7 +5,7 @@ import { defineWidget } from '../helper'; import { IWidget } from '../widgets'; const definition = defineWidget({ - id: 'torrentNetworkTraffic', + id: 'dlspeed', icon: IconClock, options: {}, diff --git a/src/widgets/useNet/UseNetTile.tsx b/src/widgets/useNet/UseNetTile.tsx index ad3b2587d..19c3e6335 100644 --- a/src/widgets/useNet/UseNetTile.tsx +++ b/src/widgets/useNet/UseNetTile.tsx @@ -32,7 +32,7 @@ dayjs.extend(duration); const downloadServiceTypes: ServiceIntegrationType['type'][] = ['sabnzbd', 'nzbGet']; const definition = defineWidget({ - id: 'useNet', + id: 'usenet', icon: IconFileDownload, options: {}, component: UseNetTile, diff --git a/src/widgets/weather/WeatherTile.tsx b/src/widgets/weather/WeatherTile.tsx index 914683f85..4684a38da 100644 --- a/src/widgets/weather/WeatherTile.tsx +++ b/src/widgets/weather/WeatherTile.tsx @@ -67,15 +67,7 @@ function WeatherTile({ className, module }: WeatherTileProps) { // TODO: add widgetWrapper that is generic and uses the definition return ( - +