diff --git a/src/tools/config/migrateConfig.ts b/src/tools/config/migrateConfig.ts index edf62c7e1..d147d9f57 100644 --- a/src/tools/config/migrateConfig.ts +++ b/src/tools/config/migrateConfig.ts @@ -1,8 +1,16 @@ +import Consola from 'consola'; import { v4 as uuidv4 } from 'uuid'; -import { AppType } from '../../types/app'; +import { AppIntegrationType, AppType, IntegrationType } from '../../types/app'; import { AreaType } from '../../types/area'; import { CategoryType } from '../../types/category'; import { ConfigType } from '../../types/config'; +import widgets from '../../widgets'; +import { IBitTorrent } from '../../widgets/bitTorrent/BitTorrentTile'; +import { IDashDotTile } from '../../widgets/dashDot/DashDotTile'; +import { IDateWidget } from '../../widgets/date/DateTile'; +import { ITorrentNetworkTraffic } from '../../widgets/torrentNetworkTraffic/TorrentNetworkTrafficTile'; +import { IWeatherWidget } from '../../widgets/weather/WeatherTile'; +import { IWidget } from '../../widgets/widgets'; import { Config, serviceItem } from '../types'; export function migrateConfig(config: Config): ConfigType { @@ -12,7 +20,7 @@ export function migrateConfig(config: Config): ConfigType { name: config.name ?? 'default', }, categories: [], - widgets: [], + widgets: migrateModules(config), apps: [], settings: { common: { @@ -26,13 +34,17 @@ export function migrateConfig(config: Config): ConfigType { defaultConfig: 'default', }, customization: { - colors: {}, + colors: { + primary: config.settings.primaryColor, + secondary: config.settings.secondaryColor, + shade: config.settings.primaryShade, + }, layout: { - enabledDocker: false, + enabledDocker: config.modules.docker?.enabled ?? false, enabledLeftSidebar: false, - enabledPing: false, + enabledPing: config.modules.ping?.enabled ?? false, enabledRightSidebar: false, - enabledSearchbar: true, + enabledSearchbar: config.modules.search?.enabled ?? true, }, }, }, @@ -122,10 +134,7 @@ const migrateService = ( appearance: { iconUrl: migrateIcon(oldService.icon), }, - integration: { - type: null, - properties: [], - }, + integration: migrateIntegration(oldService), area: areaType, shape: { lg: getShapeForColumnCount(serviceIndex, 12), @@ -134,13 +143,259 @@ const migrateService = ( }, }); +const migrateModules = (config: Config): IWidget[] => { + const moduleKeys = Object.keys(config.modules); + return moduleKeys + .map((moduleKey): IWidget | null => { + const oldModule = config.modules[moduleKey]; + + if (!oldModule.enabled) { + return null; + } + + switch (moduleKey.toLowerCase()) { + case 'torrent-status': + case 'Torrent': + return { + id: uuidv4(), + properties: { + refreshInterval: 10, + displayCompletedTorrents: oldModule.options?.hideComplete?.value ?? false, + displayStaleTorrents: true, + }, + area: { + type: 'wrapper', + properties: { + id: 'default', + }, + }, + } as IBitTorrent; + case 'weather': + return { + id: uuidv4(), + properties: { + displayInFahrenheit: oldModule.options?.freedomunit?.value ?? false, + location: oldModule.options?.location?.value ?? 'Paris', + }, + } as IWeatherWidget; + case 'dashdot': + case 'Dash.': + return { + id: uuidv4(), + properties: { + url: oldModule.options?.url?.value ?? '', + cpuMultiView: oldModule.options?.cpuMultiView?.value ?? false, + storageMultiView: oldModule.options?.storageMultiView?.value ?? false, + useCompactView: oldModule.options?.useCompactView?.value ?? false, + graphs: oldModule.options?.graphs?.value ?? ['cpu', 'ram'], + }, + } as IDashDotTile; + case 'date': + return { + id: uuidv4(), + properties: { + display24HourFormat: oldModule.options?.full?.value ?? true, + }, + } as IDateWidget; + case 'Download Speed': + case 'dlspeed': + return { + id: uuidv4(), + properties: {}, + } as ITorrentNetworkTraffic; + default: + Consola.error(`Failed to map unknown module type ${moduleKey} to new type definitions.`); + return null; + } + }) + .filter((x) => x !== null) as IWidget[]; +}; + const migrateIcon = (iconUrl: string) => { if (iconUrl.startsWith('https://cdn.jsdelivr.net/gh/walkxhub/dashboard-icons/png/')) { - console.log('migrating icon:'); const icon = iconUrl.split('/').at(-1); - console.log(`${iconUrl} -> ${icon}`); + Consola.warn( + `Detected legacy icon repository. Upgrading to replacement repository: ${iconUrl} -> ${icon}` + ); return `https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons/png/${icon}`; } return iconUrl; }; + +const migrateIntegration = (oldService: serviceItem): AppIntegrationType => { + const logInformation = (newType: IntegrationType) => { + Consola.info(`Migrated integration ${oldService.type} to the new type ${newType}`); + }; + switch (oldService.type) { + case 'Deluge': + logInformation('deluge'); + return { + type: 'deluge', + properties: [ + { + field: 'password', + isDefined: oldService.password !== undefined, + type: 'private', + value: oldService.password, + }, + ], + }; + case 'Jellyseerr': + logInformation('jellyseerr'); + return { + type: 'jellyseerr', + properties: [ + { + field: 'apiKey', + isDefined: oldService.apiKey !== undefined, + type: 'private', + value: oldService.apiKey, + }, + ], + }; + case 'Overseerr': + logInformation('overseerr'); + return { + type: 'overseerr', + properties: [ + { + field: 'apiKey', + isDefined: oldService.apiKey !== undefined, + type: 'private', + value: oldService.apiKey, + }, + ], + }; + case 'Lidarr': + logInformation('lidarr'); + return { + type: 'lidarr', + properties: [ + { + field: 'apiKey', + isDefined: oldService.apiKey !== undefined, + type: 'private', + value: oldService.apiKey, + }, + ], + }; + case 'Radarr': + logInformation('radarr'); + return { + type: 'radarr', + properties: [ + { + field: 'apiKey', + isDefined: oldService.apiKey !== undefined, + type: 'private', + value: oldService.apiKey, + }, + ], + }; + case 'Readarr': + logInformation('readarr'); + return { + type: 'readarr', + properties: [ + { + field: 'apiKey', + isDefined: oldService.apiKey !== undefined, + type: 'private', + value: oldService.apiKey, + }, + ], + }; + case 'Sabnzbd': + logInformation('sabnzbd'); + return { + type: 'sabnzbd', + properties: [ + { + field: 'apiKey', + isDefined: oldService.apiKey !== undefined, + type: 'private', + value: oldService.apiKey, + }, + ], + }; + case 'Sonarr': + logInformation('sonarr'); + return { + type: 'sonarr', + properties: [ + { + field: 'apiKey', + isDefined: oldService.apiKey !== undefined, + type: 'private', + value: oldService.apiKey, + }, + ], + }; + case 'NZBGet': + logInformation('nzbGet'); + return { + type: 'nzbGet', + properties: [ + { + field: 'username', + isDefined: oldService.username !== undefined, + type: 'private', + value: oldService.username, + }, + { + field: 'password', + isDefined: oldService.password !== undefined, + type: 'private', + value: oldService.password, + }, + ], + }; + case 'qBittorrent': + logInformation('qBittorrent'); + return { + type: 'qBittorrent', + properties: [ + { + field: 'username', + isDefined: oldService.username !== undefined, + type: 'private', + value: oldService.username, + }, + { + field: 'password', + isDefined: oldService.password !== undefined, + type: 'private', + value: oldService.password, + }, + ], + }; + case 'Transmission': + logInformation('transmission'); + return { + type: 'transmission', + properties: [ + { + field: 'username', + isDefined: oldService.username !== undefined, + type: 'private', + value: oldService.username, + }, + { + field: 'password', + isDefined: oldService.password !== undefined, + type: 'private', + value: oldService.password, + }, + ], + }; + default: + Consola.warn( + `Integration type of service ${oldService.name} could not be mapped to new integration type definition` + ); + return { + type: null, + properties: [], + }; + } +}; diff --git a/src/widgets/bitTorrent/BitTorrentTile.tsx b/src/widgets/bitTorrent/BitTorrentTile.tsx index e6d2368cf..0c60a7a51 100644 --- a/src/widgets/bitTorrent/BitTorrentTile.tsx +++ b/src/widgets/bitTorrent/BitTorrentTile.tsx @@ -44,7 +44,7 @@ const definition = defineWidget({ }, refreshInterval: { type: 'slider', - defaultValue: 1, + defaultValue: 10, min: 1, max: 60, step: 1, diff --git a/src/widgets/dashDot/DashDotTile.tsx b/src/widgets/dashDot/DashDotTile.tsx index fcf8271c1..cfb80cfb1 100644 --- a/src/widgets/dashDot/DashDotTile.tsx +++ b/src/widgets/dashDot/DashDotTile.tsx @@ -60,13 +60,13 @@ function DashDotTile({ widget }: DashDotTileProps) { dashDotUrl, }); - const graphs = widget?.properties.graphs.map((g) => ({ - id: g, - name: t(`card.graphs.${g}.title`), - twoSpan: ['network', 'gpu'].includes(g), + const graphs = widget?.properties.graphs.map((graph) => ({ + id: graph, + name: t(`card.graphs.${graph}.title`), + twoSpan: ['network', 'gpu'].includes(graph), isMultiView: - (g === 'cpu' && widget.properties.cpuMultiView) || - (g === 'storage' && widget.properties.storageMultiView), + (graph === 'cpu' && widget.properties.cpuMultiView) || + (graph === 'storage' && widget.properties.storageMultiView), })); const heading = ( diff --git a/src/widgets/widgets.d.ts b/src/widgets/widgets.ts similarity index 96% rename from src/widgets/widgets.d.ts rename to src/widgets/widgets.ts index 19e41ed12..10ef46858 100644 --- a/src/widgets/widgets.d.ts +++ b/src/widgets/widgets.ts @@ -1,5 +1,7 @@ import { TablerIcon } from '@tabler/icons'; import React from 'react'; +import { AreaType } from '../types/area'; +import { ShapeType } from '../types/shape'; // Type of widgets which are safed to config export type IWidget = {