refactor: revert assignment of oldmarr widget mapping (#1780)

This commit is contained in:
Meier Lukas
2024-12-26 08:58:06 +01:00
committed by GitHub
parent e37279fe80
commit ef24370a8c
5 changed files with 73 additions and 50 deletions

View File

@@ -11,3 +11,8 @@ export type RemoveReadonly<T> = {
}; };
export type MaybeArray<T> = T | T[]; export type MaybeArray<T> = T | T[];
export type Inverse<T extends Invertible> = {
[Key in keyof T as T[Key]]: Key;
};
type Invertible = Record<PropertyKey, PropertyKey>;

View File

@@ -55,7 +55,7 @@ export const insertItemsAsync = async (
xOffset: screenSizeShape.location.x, xOffset: screenSizeShape.location.x,
yOffset: screenSizeShape.location.y, yOffset: screenSizeShape.location.y,
kind, kind,
options: SuperJSON.stringify(mapOptions(kind, widget.properties, appsMap)), options: SuperJSON.stringify(mapOptions(widget.type, widget.properties, appsMap)),
}); });
logger.debug(`Inserted widget id=${widget.id} sectionId=${sectionId}`); logger.debug(`Inserted widget id=${widget.id} sectionId=${sectionId}`);

View File

@@ -83,7 +83,11 @@ export const mapWidget = (
yOffset: shapeForSize.location.y, yOffset: shapeForSize.location.y,
kind, kind,
options: SuperJSON.stringify( options: SuperJSON.stringify(
mapOptions(kind, widget.properties, new Map([...appsMap.entries()].map(([key, value]) => [key, value.id]))), mapOptions(
widget.type,
widget.properties,
new Map([...appsMap.entries()].map(([key, value]) => [key, value.id])),
),
), ),
}; };
}; };

View File

@@ -1,4 +1,5 @@
import { objectEntries } from "@homarr/common"; import { objectEntries } from "@homarr/common";
import type { Inverse } from "@homarr/common/types";
import type { WidgetKind } from "@homarr/definitions"; import type { WidgetKind } from "@homarr/definitions";
import type { OldmarrBookmarkDefinition } from "./bookmark"; import type { OldmarrBookmarkDefinition } from "./bookmark";
@@ -49,32 +50,32 @@ export type OldmarrWidgetDefinitions =
| OldmarrMediaTranscodingDefinition; | OldmarrMediaTranscodingDefinition;
export const widgetKindMapping = { export const widgetKindMapping = {
app: null, // In oldmarr apps were not widgets date: "clock",
clock: "date",
calendar: "calendar", calendar: "calendar",
downloads: "torrents-status", "torrents-status": "downloads",
weather: "weather", weather: "weather",
rssFeed: "rss", rss: "rssFeed",
video: "video-stream", "video-stream": "video",
iframe: "iframe", iframe: "iframe",
mediaServer: "media-server", "media-server": "mediaServer",
dnsHoleSummary: "dns-hole-summary", "dns-hole-summary": "dnsHoleSummary",
dnsHoleControls: "dns-hole-controls", "dns-hole-controls": "dnsHoleControls",
notebook: "notebook", notebook: "notebook",
"smartHome-entityState": "smart-home/entity-state", "smart-home/entity-state": "smartHome-entityState",
"smartHome-executeAutomation": "smart-home/trigger-automation", "smart-home/trigger-automation": "smartHome-executeAutomation",
"mediaRequests-requestList": "media-requests-list", "media-requests-list": "mediaRequests-requestList",
"mediaRequests-requestStats": "media-requests-stats", "media-requests-stats": "mediaRequests-requestStats",
indexerManager: "indexer-manager", "indexer-manager": "indexerManager",
bookmarks: "bookmark", bookmark: "bookmarks",
healthMonitoring: "health-monitoring", "health-monitoring": "healthMonitoring",
mediaTranscoding: "media-transcoding", dashdot: "healthMonitoring",
} satisfies Record<WidgetKind, OldmarrWidgetDefinitions["id"] | null>; "media-transcoding": "mediaTranscoding",
// Use null for widgets that did not exist in oldmarr dlspeed: null,
// TODO: revert assignment so that only old widgets are needed in the object, usenet: "downloads",
// this can be done ones all widgets are implemented } satisfies Record<OldmarrWidgetDefinitions["id"], WidgetKind | null>;
export type WidgetMapping = typeof widgetKindMapping; export type WidgetMapping = typeof widgetKindMapping;
export type InversedWidgetMapping = Inverse<Omit<typeof widgetKindMapping, "dlspeed">>;
export const mapKind = (kind: OldmarrWidgetDefinitions["id"]): WidgetKind | undefined => export const mapKind = (kind: OldmarrWidgetDefinitions["id"]): keyof InversedWidgetMapping | null =>
objectEntries(widgetKindMapping).find(([_, value]) => value === kind)?.[0]; objectEntries(widgetKindMapping).find(([key]) => key === kind)?.[1] ?? null;

View File

@@ -1,18 +1,18 @@
import { objectEntries } from "@homarr/common"; import { objectEntries } from "@homarr/common";
import type { WidgetKind } from "@homarr/definitions";
import { logger } from "@homarr/log"; import { logger } from "@homarr/log";
import type { WidgetComponentProps } from "../../../widgets/src/definition"; import type { WidgetComponentProps } from "../../../widgets/src/definition";
import type { OldmarrWidgetDefinitions, WidgetMapping } from "./definitions"; import { mapKind } from "./definitions";
import type { InversedWidgetMapping, OldmarrWidgetDefinitions, WidgetMapping } from "./definitions";
// This type enforces, that for all widget mappings there is a corresponding option mapping, // This type enforces, that for all widget mappings there is a corresponding option mapping,
// each option of newmarr can be mapped from the value of the oldmarr options // each option of newmarr can be mapped from the value of the oldmarr options
type OptionMapping = { type OptionMapping = {
[WidgetKey in keyof WidgetMapping]: WidgetMapping[WidgetKey] extends null [WidgetKey in keyof InversedWidgetMapping]: InversedWidgetMapping[WidgetKey] extends null
? null ? null
: { : {
[OptionsKey in keyof WidgetComponentProps<WidgetKey>["options"]]: ( [OptionsKey in keyof WidgetComponentProps<WidgetKey>["options"]]: (
oldOptions: Extract<OldmarrWidgetDefinitions, { id: WidgetMapping[WidgetKey] }>["options"], oldOptions: Extract<OldmarrWidgetDefinitions, { id: InversedWidgetMapping[WidgetKey] }>["options"],
appsMap: Map<string, string>, appsMap: Map<string, string>,
) => WidgetComponentProps<WidgetKey>["options"][OptionsKey] | undefined; ) => WidgetComponentProps<WidgetKey>["options"][OptionsKey] | undefined;
}; };
@@ -55,12 +55,16 @@ const optionMapping: OptionMapping = {
useCustomTimezone: () => true, useCustomTimezone: () => true,
}, },
downloads: { downloads: {
activeTorrentThreshold: (oldOptions) => oldOptions.speedLimitOfActiveTorrents, activeTorrentThreshold: (oldOptions) =>
applyFilterToRatio: (oldOptions) => oldOptions.displayRatioWithFilter, "speedLimitOfActiveTorrents" in oldOptions ? oldOptions.speedLimitOfActiveTorrents : undefined,
categoryFilter: (oldOptions) => oldOptions.labelFilter, applyFilterToRatio: (oldOptions) =>
filterIsWhitelist: (oldOptions) => oldOptions.labelFilterIsWhitelist, "displayRatioWithFilter" in oldOptions ? oldOptions.displayRatioWithFilter : undefined,
enableRowSorting: (oldOptions) => oldOptions.rowSorting, categoryFilter: (oldOptions) => ("labelFilter" in oldOptions ? oldOptions.labelFilter : undefined),
showCompletedTorrent: (oldOptions) => oldOptions.displayCompletedTorrents, filterIsWhitelist: (oldOptions) =>
"labelFilterIsWhitelist" in oldOptions ? oldOptions.labelFilterIsWhitelist : undefined,
enableRowSorting: (oldOptions) => ("rowSorting" in oldOptions ? oldOptions.rowSorting : undefined),
showCompletedTorrent: (oldOptions) =>
"displayCompletedTorrents" in oldOptions ? oldOptions.displayCompletedTorrents : undefined,
columns: () => ["integration", "name", "progress", "time", "actions"], columns: () => ["integration", "name", "progress", "time", "actions"],
defaultSort: () => "type", defaultSort: () => "type",
descendingDefaultSort: () => false, descendingDefaultSort: () => false,
@@ -124,45 +128,54 @@ const optionMapping: OptionMapping = {
openIndexerSiteInNewTab: (oldOptions) => oldOptions.openIndexerSiteInNewTab, openIndexerSiteInNewTab: (oldOptions) => oldOptions.openIndexerSiteInNewTab,
}, },
healthMonitoring: { healthMonitoring: {
cpu: (oldOptions) => oldOptions.cpu, cpu: (oldOptions) =>
memory: (oldOptions) => oldOptions.memory, "cpu" in oldOptions
fahrenheit: (oldOptions) => oldOptions.fahrenheit, ? oldOptions.cpu
fileSystem: (oldOptions) => oldOptions.fileSystem, : oldOptions.graphsOrder.some((graph) => graph.key === "cpu" && graph.subValues.enabled),
memory: (oldOptions) =>
"memory" in oldOptions
? oldOptions.memory
: oldOptions.graphsOrder.some((graph) => graph.key === "ram" && graph.subValues.enabled),
fahrenheit: (oldOptions) => ("fahrenheit" in oldOptions ? oldOptions.fahrenheit : undefined),
fileSystem: (oldOptions) =>
"fileSystem" in oldOptions
? oldOptions.fileSystem
: oldOptions.graphsOrder.some((graph) => graph.key === "storage" && graph.subValues.enabled),
}, },
mediaTranscoding: { mediaTranscoding: {
defaultView: (oldOptions) => oldOptions.defaultView, defaultView: (oldOptions) => oldOptions.defaultView,
queuePageSize: (oldOptions) => oldOptions.queuePageSize, queuePageSize: (oldOptions) => oldOptions.queuePageSize,
}, },
app: null,
}; };
/** /**
* Maps the oldmarr options to the newmarr options * Maps the oldmarr options to the newmarr options
* @param kind item kind to map * @param type old widget type
* @param oldOptions oldmarr options for this item * @param oldOptions oldmarr options for this item
* @param appsMap map of old app ids to new app ids * @param appsMap map of old app ids to new app ids
* @returns newmarr options for this item or null if the item did not exist in oldmarr * @returns newmarr options for this item or null if the item did not exist in oldmarr
*/ */
export const mapOptions = <K extends WidgetKind>( export const mapOptions = <K extends OldmarrWidgetDefinitions["id"]>(
kind: K, type: K,
oldOptions: Extract<OldmarrWidgetDefinitions, { id: WidgetMapping[K] }>["options"], oldOptions: Extract<OldmarrWidgetDefinitions, { id: K }>["options"],
appsMap: Map<string, string>, appsMap: Map<string, string>,
) => { ) => {
logger.debug(`Mapping old homarr options for widget kind=${kind} options=${JSON.stringify(oldOptions)}`); logger.debug(`Mapping old homarr options for widget type=${type} options=${JSON.stringify(oldOptions)}`);
if (optionMapping[kind] === null) { const kind = mapKind(type);
if (!kind) {
return null; return null;
} }
const mapping = optionMapping[kind]; const mapping = optionMapping[kind];
return objectEntries(mapping).reduce( return objectEntries(mapping).reduce(
(acc, [key, value]) => { (acc, [key, value]: [string, (oldOptions: Record<string, unknown>, appsMap: Map<string, string>) => unknown]) => {
const newValue = value(oldOptions as never, appsMap); const newValue = value(oldOptions, appsMap);
logger.debug(`Mapping old homarr option kind=${kind} key=${key as string} newValue=${newValue as string}`); logger.debug(`Mapping old homarr option kind=${kind} key=${key} newValue=${newValue as string}`);
if (newValue !== undefined) { if (newValue !== undefined) {
acc[key as string] = newValue; acc[key] = newValue;
} }
return acc; return acc;
}, },
{} as Record<string, unknown>, {} as Record<string, unknown>,
) as WidgetComponentProps<K>["options"]; ) as WidgetComponentProps<Exclude<WidgetMapping[K], null>>["options"];
}; };