refactor: revert assignment of oldmarr widget mapping (#1780)
This commit is contained in:
@@ -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>;
|
||||||
|
|||||||
@@ -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}`);
|
||||||
|
|||||||
@@ -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])),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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"];
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user