Files
Homarr/src/tools/config/migrateConfig.ts

483 lines
13 KiB
TypeScript
Raw Normal View History

import Consola from 'consola';
import { v4 as uuidv4 } from 'uuid';
import { AppIntegrationType, AppType, IntegrationType } from '../../types/app';
import { AreaType } from '../../types/area';
import { CategoryType } from '../../types/category';
2022-12-22 11:29:51 +09:00
import { ConfigType } from '../../types/config';
2023-01-10 21:51:52 +01:00
import { SearchEngineCommonSettingsType } from '../../types/settings';
import { IBitTorrent } from '../../widgets/bitTorrent/BitTorrentTile';
2023-01-08 13:30:25 +09:00
import { ICalendarWidget } from '../../widgets/calendar/CalendarTile';
import { IDashDotTile } from '../../widgets/dashDot/DashDotTile';
import { IDateWidget } from '../../widgets/date/DateTile';
import { ITorrentNetworkTraffic } from '../../widgets/torrentNetworkTraffic/TorrentNetworkTrafficTile';
2023-01-08 13:30:25 +09:00
import { IUsenetWidget } from '../../widgets/useNet/UseNetTile';
import { IWeatherWidget } from '../../widgets/weather/WeatherTile';
import { IWidget } from '../../widgets/widgets';
import { Config, serviceItem } from '../types';
2022-12-22 11:29:51 +09:00
export function migrateConfig(config: Config): ConfigType {
2022-12-22 11:29:51 +09:00
const newConfig: ConfigType = {
2022-12-24 17:18:16 +09:00
schemaVersion: 1,
2022-12-22 11:29:51 +09:00
configProperties: {
name: config.name ?? 'default',
},
categories: [],
widgets: migrateModules(config),
2022-12-22 11:29:51 +09:00
apps: [],
settings: {
common: {
2023-01-10 21:51:52 +01:00
searchEngine: migrateSearchEngine(config),
2022-12-22 11:29:51 +09:00
defaultConfig: 'default',
},
customization: {
colors: {
2023-01-07 23:25:13 +01:00
primary: config.settings.primaryColor ?? 'red',
secondary: config.settings.secondaryColor ?? 'orange',
shade: config.settings.primaryShade ?? 7,
},
2022-12-22 11:29:51 +09:00
layout: {
enabledDocker: config.modules.docker?.enabled ?? false,
2022-12-22 11:29:51 +09:00
enabledLeftSidebar: false,
enabledPing: config.modules.ping?.enabled ?? false,
2022-12-22 11:29:51 +09:00
enabledRightSidebar: false,
enabledSearchbar: config.modules.search?.enabled ?? true,
2022-12-22 11:29:51 +09:00
},
},
},
wrappers: [
{
id: 'default',
position: 1,
},
],
};
config.services.forEach((service) => {
const { category: categoryName } = service;
if (!categoryName) {
newConfig.apps.push(
2023-01-07 23:25:13 +01:00
migrateService(service, {
type: 'wrapper',
properties: {
id: 'default',
},
})
);
return;
}
const category = getConfigAndCreateIfNotExsists(newConfig, categoryName);
if (!category) {
return;
}
newConfig.apps.push(
2023-01-07 23:25:13 +01:00
migrateService(service, { type: 'category', properties: { id: category.id } })
);
});
2022-12-22 11:29:51 +09:00
return newConfig;
}
2023-01-10 21:51:52 +01:00
const migrateSearchEngine = (config: Config): SearchEngineCommonSettingsType => {
switch (config.settings.searchUrl) {
case 'https://bing.com/search?q=':
return {
type: 'bing',
properties: {
enabled: true,
openInNewTab: true,
},
};
case 'https://google.com/search?q=':
return {
type: 'google',
properties: {
enabled: true,
openInNewTab: true,
},
};
case 'https://duckduckgo.com/?q=':
return {
type: 'duckDuckGo',
properties: {
enabled: true,
openInNewTab: true,
},
};
default:
return {
type: 'custom',
properties: {
enabled: true,
openInNewTab: true,
template: config.settings.searchUrl,
},
};
}
};
const getConfigAndCreateIfNotExsists = (
config: ConfigType,
categoryName: string
): CategoryType | null => {
const foundCategory = config.categories.find((c) => c.name === categoryName);
if (foundCategory) {
return foundCategory;
}
const category: CategoryType = {
id: uuidv4(),
name: categoryName,
position: config.categories.length + 1, // sync up with index of categories
};
config.categories.push(category);
// sync up with categories
if (config.wrappers.length < config.categories.length) {
config.wrappers.push({
id: uuidv4(),
position: config.wrappers.length + 1, // sync up with index of categories
});
}
return category;
};
2023-01-07 23:25:13 +01:00
const migrateService = (oldService: serviceItem, areaType: AreaType): AppType => ({
id: uuidv4(),
name: oldService.name,
url: oldService.url,
behaviour: {
isOpeningNewTab: oldService.newTab ?? true,
externalUrl: oldService.openedUrl ?? '',
},
network: {
enabledStatusChecker: oldService.ping ?? true,
okStatus: oldService.status?.map((str) => parseInt(str, 10)) ?? [200],
},
appearance: {
2023-01-07 19:14:40 +01:00
iconUrl: migrateIcon(oldService.icon),
},
integration: migrateIntegration(oldService),
area: areaType,
2023-01-07 23:25:13 +01:00
shape: {},
});
2023-01-07 19:14:40 +01:00
const migrateModules = (config: Config): IWidget<string, any>[] => {
const moduleKeys = Object.keys(config.modules);
return moduleKeys
.map((moduleKey): IWidget<string, any> | null => {
const oldModule = config.modules[moduleKey];
if (!oldModule.enabled) {
return null;
}
switch (moduleKey.toLowerCase()) {
case 'torrent-status':
case 'Torrent':
return {
2023-01-08 13:30:25 +09:00
id: 'torrents-status',
properties: {
refreshInterval: 10,
displayCompletedTorrents: oldModule.options?.hideComplete?.value ?? false,
displayStaleTorrents: true,
},
area: {
type: 'wrapper',
properties: {
id: 'default',
},
},
shape: {},
} as IBitTorrent;
case 'weather':
return {
2023-01-08 13:30:25 +09:00
id: 'weather',
properties: {
displayInFahrenheit: oldModule.options?.freedomunit?.value ?? false,
location: oldModule.options?.location?.value ?? 'Paris',
},
area: {
type: 'wrapper',
properties: {
id: 'default',
},
},
shape: {},
} as IWeatherWidget;
case 'dashdot':
case 'Dash.':
return {
2023-01-08 13:30:25 +09:00
id: 'dashdot',
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'],
},
area: {
type: 'wrapper',
properties: {
id: 'default',
},
},
shape: {},
} as IDashDotTile;
case 'date':
return {
2023-01-08 13:30:25 +09:00
id: 'date',
properties: {
display24HourFormat: oldModule.options?.full?.value ?? true,
},
area: {
type: 'wrapper',
properties: {
id: 'default',
},
},
shape: {},
} as IDateWidget;
2023-01-08 13:30:25 +09:00
case 'Download Speed' || 'dlspeed':
return {
2023-01-08 13:30:25 +09:00
id: 'dlspeed',
properties: {},
area: {
type: 'wrapper',
properties: {
id: 'default',
},
},
shape: {},
} as ITorrentNetworkTraffic;
2023-01-08 13:30:25 +09:00
case 'calendar':
return {
id: 'calendar',
properties: {},
area: {
type: 'wrapper',
properties: {
id: 'default',
},
},
shape: {},
} as ICalendarWidget;
case 'usenet':
return {
id: 'usenet',
properties: {},
area: {
type: 'wrapper',
properties: {
id: 'default',
},
},
shape: {},
} as IUsenetWidget;
default:
Consola.error(`Failed to map unknown module type ${moduleKey} to new type definitions.`);
return null;
}
})
.filter((x) => x !== null) as IWidget<string, any>[];
};
2023-01-07 19:14:40 +01:00
const migrateIcon = (iconUrl: string) => {
if (iconUrl.startsWith('https://cdn.jsdelivr.net/gh/walkxhub/dashboard-icons/png/')) {
const icon = iconUrl.split('/').at(-1);
Consola.warn(
`Detected legacy icon repository. Upgrading to replacement repository: ${iconUrl} -> ${icon}`
);
2023-01-07 19:14:40 +01:00
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,
},
],
};
2023-01-08 12:47:06 +09:00
case 'Other':
return {
type: null,
properties: [],
};
default:
Consola.warn(
`Integration type of service ${oldService.name} could not be mapped to new integration type definition`
);
return {
type: null,
properties: [],
};
}
};