fix(import): autofix missing sizes of items with grid-algorithm (#2522)
This commit is contained in:
@@ -81,7 +81,7 @@ export const createBoardInsertCollection = (
|
|||||||
...boardSizes.map((size) => ({
|
...boardSizes.map((size) => ({
|
||||||
id: layoutMapping[size],
|
id: layoutMapping[size],
|
||||||
boardId: mappedBoard.id,
|
boardId: mappedBoard.id,
|
||||||
columnCount: mapColumnCount(board.config, size),
|
columnCount: mapColumnCount(board.config.settings.customization.gridstack, size),
|
||||||
breakpoint: mapBreakpoint(size),
|
breakpoint: mapBreakpoint(size),
|
||||||
name: getBoardSizeName(size),
|
name: getBoardSizeName(size),
|
||||||
})),
|
})),
|
||||||
@@ -94,7 +94,17 @@ export const createBoardInsertCollection = (
|
|||||||
}
|
}
|
||||||
logger.debug(`Added sections to board insert collection count=${insertCollection.sections.length}`);
|
logger.debug(`Added sections to board insert collection count=${insertCollection.sections.length}`);
|
||||||
|
|
||||||
const preparedItems = prepareItems({ apps, widgets }, appsMap, preparedSections, layoutMapping, mappedBoard.id);
|
const preparedItems = prepareItems(
|
||||||
|
{
|
||||||
|
apps,
|
||||||
|
widgets,
|
||||||
|
settings: board.config.settings,
|
||||||
|
},
|
||||||
|
appsMap,
|
||||||
|
preparedSections,
|
||||||
|
layoutMapping,
|
||||||
|
mappedBoard.id,
|
||||||
|
);
|
||||||
preparedItems.forEach(({ layouts, ...item }) => {
|
preparedItems.forEach(({ layouts, ...item }) => {
|
||||||
insertCollection.items.push(item);
|
insertCollection.items.push(item);
|
||||||
insertCollection.itemLayouts.push(...layouts);
|
insertCollection.itemLayouts.push(...layouts);
|
||||||
|
|||||||
@@ -1,13 +1,16 @@
|
|||||||
import type { BoardSize, OldmarrConfig } from "@homarr/old-schema";
|
import type { BoardSize, OldmarrConfig } from "@homarr/old-schema";
|
||||||
|
|
||||||
export const mapColumnCount = (old: OldmarrConfig, screenSize: BoardSize) => {
|
export const mapColumnCount = (
|
||||||
|
gridstackSettings: OldmarrConfig["settings"]["customization"]["gridstack"],
|
||||||
|
screenSize: BoardSize,
|
||||||
|
) => {
|
||||||
switch (screenSize) {
|
switch (screenSize) {
|
||||||
case "lg":
|
case "lg":
|
||||||
return old.settings.customization.gridstack.columnCountLarge;
|
return gridstackSettings.columnCountLarge;
|
||||||
case "md":
|
case "md":
|
||||||
return old.settings.customization.gridstack.columnCountMedium;
|
return gridstackSettings.columnCountMedium;
|
||||||
case "sm":
|
case "sm":
|
||||||
return old.settings.customization.gridstack.columnCountSmall;
|
return gridstackSettings.columnCountSmall;
|
||||||
default:
|
default:
|
||||||
return 10;
|
return 10;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -135,7 +135,7 @@ const moveWidgetsAndAppsInLeftSidebar = (
|
|||||||
offset: number,
|
offset: number,
|
||||||
screenSize: BoardSize,
|
screenSize: BoardSize,
|
||||||
) => {
|
) => {
|
||||||
const columnCount = mapColumnCount(old, screenSize);
|
const columnCount = mapColumnCount(old.settings.customization.gridstack, screenSize);
|
||||||
let requiredHeight = updateItems({
|
let requiredHeight = updateItems({
|
||||||
// This should work as the reference of the items did not change, only the array reference did
|
// This should work as the reference of the items did not change, only the array reference did
|
||||||
items: [...old.widgets, ...old.apps],
|
items: [...old.widgets, ...old.apps],
|
||||||
@@ -211,7 +211,7 @@ const moveWidgetsAndAppsInRightSidebar = (
|
|||||||
offset: number,
|
offset: number,
|
||||||
screenSize: BoardSize,
|
screenSize: BoardSize,
|
||||||
) => {
|
) => {
|
||||||
const columnCount = mapColumnCount(old, screenSize);
|
const columnCount = mapColumnCount(old.settings.customization.gridstack, screenSize);
|
||||||
const xOffsetDelta = Math.max(columnCount - 2, 0);
|
const xOffsetDelta = Math.max(columnCount - 2, 0);
|
||||||
const requiredHeight = updateItems({
|
const requiredHeight = updateItems({
|
||||||
// This should work as the reference of the items did not change, only the array reference did
|
// This should work as the reference of the items did not change, only the array reference did
|
||||||
|
|||||||
@@ -1,15 +1,101 @@
|
|||||||
import type { BoardSize, OldmarrConfig } from "@homarr/old-schema";
|
import { logger } from "@homarr/log";
|
||||||
|
import type { BoardSize, OldmarrApp, OldmarrConfig, OldmarrWidget, SizedShape } from "@homarr/old-schema";
|
||||||
|
import { boardSizes } from "@homarr/old-schema";
|
||||||
|
|
||||||
|
import type { GridAlgorithmItem } from "../../../api/src/router/board/grid-algorithm";
|
||||||
|
import { generateResponsiveGridFor } from "../../../api/src/router/board/grid-algorithm";
|
||||||
|
import { mapColumnCount } from "../mappers/map-column-count";
|
||||||
import { mapApp, mapWidget } from "../mappers/map-item";
|
import { mapApp, mapWidget } from "../mappers/map-item";
|
||||||
|
|
||||||
export const prepareItems = (
|
export const prepareItems = (
|
||||||
{ apps, widgets }: Pick<OldmarrConfig, "apps" | "widgets">,
|
{ apps, widgets, settings }: Pick<OldmarrConfig, "apps" | "widgets" | "settings">,
|
||||||
appsMap: Map<string, { id: string }>,
|
appsMap: Map<string, { id: string }>,
|
||||||
sectionMap: Map<string, { id: string }>,
|
sectionMap: Map<string, { id: string }>,
|
||||||
layoutMap: Record<BoardSize, string>,
|
layoutMap: Record<BoardSize, string>,
|
||||||
boardId: string,
|
boardId: string,
|
||||||
) =>
|
) => {
|
||||||
widgets
|
let localApps = apps;
|
||||||
|
let localWidgets = widgets;
|
||||||
|
|
||||||
|
const incompleteSizes = boardSizes.filter((size) =>
|
||||||
|
widgets
|
||||||
|
.map((widget) => widget.shape)
|
||||||
|
.concat(apps.map((app) => app.shape))
|
||||||
|
.some((shape) => !shape[size]),
|
||||||
|
);
|
||||||
|
|
||||||
|
if (incompleteSizes.length > 0) {
|
||||||
|
logger.warn(
|
||||||
|
`Found items with incomplete sizes board=${boardId} count=${incompleteSizes.length} sizes=${incompleteSizes.join(", ")}\nHomarr will automatically generate missing sizes`,
|
||||||
|
);
|
||||||
|
|
||||||
|
incompleteSizes.forEach((size) => {
|
||||||
|
const columnCount = mapColumnCount(settings.customization.gridstack, size);
|
||||||
|
const previousSize = !incompleteSizes.includes("lg") ? "lg" : incompleteSizes.includes("sm") ? "md" : "sm";
|
||||||
|
const previousWidth = mapColumnCount(settings.customization.gridstack, previousSize);
|
||||||
|
logger.info(`Generating missing size boardId=${boardId} from=${previousSize} to=${size}`);
|
||||||
|
|
||||||
|
const items = widgets
|
||||||
|
.map((item) => mapItemForGridAlgorithm(item, previousSize))
|
||||||
|
.concat(apps.map((item) => mapItemForGridAlgorithm(item, previousSize)));
|
||||||
|
|
||||||
|
const distinctSectionIds = [...new Set(items.map((item) => item.sectionId))];
|
||||||
|
distinctSectionIds.forEach((sectionId) => {
|
||||||
|
const { items: newItems } = generateResponsiveGridFor({ items, previousWidth, width: columnCount, sectionId });
|
||||||
|
|
||||||
|
localApps = localApps.map((app) => {
|
||||||
|
const item = newItems.find((item) => item.id === app.id);
|
||||||
|
if (!item) return app;
|
||||||
|
|
||||||
|
return {
|
||||||
|
...app,
|
||||||
|
shape: {
|
||||||
|
...app.shape,
|
||||||
|
[size]: mapShapeFromGridAlgorithm(item),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
localWidgets = localWidgets.map((widget) => {
|
||||||
|
const item = newItems.find((item) => item.id === widget.id);
|
||||||
|
if (!item) return widget;
|
||||||
|
|
||||||
|
return {
|
||||||
|
...widget,
|
||||||
|
shape: {
|
||||||
|
...widget.shape,
|
||||||
|
[size]: mapShapeFromGridAlgorithm(item),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return localWidgets
|
||||||
.map((widget) => mapWidget(widget, appsMap, sectionMap, layoutMap, boardId))
|
.map((widget) => mapWidget(widget, appsMap, sectionMap, layoutMap, boardId))
|
||||||
.concat(apps.map((app) => mapApp(app, appsMap, sectionMap, layoutMap, boardId)))
|
.concat(localApps.map((app) => mapApp(app, appsMap, sectionMap, layoutMap, boardId)))
|
||||||
.filter((widget) => widget !== null);
|
.filter((widget) => widget !== null);
|
||||||
|
};
|
||||||
|
|
||||||
|
const mapItemForGridAlgorithm = (item: OldmarrApp | OldmarrWidget, size: BoardSize): GridAlgorithmItem => ({
|
||||||
|
width: item.shape[size]?.size.width ?? 1,
|
||||||
|
height: item.shape[size]?.size.height ?? 1,
|
||||||
|
xOffset: item.shape[size]?.location.x ?? 0,
|
||||||
|
yOffset: item.shape[size]?.location.y ?? 0,
|
||||||
|
sectionId: item.area.type === "sidebar" ? item.area.properties.location : item.area.properties.id,
|
||||||
|
id: item.id,
|
||||||
|
type: "item",
|
||||||
|
});
|
||||||
|
|
||||||
|
const mapShapeFromGridAlgorithm = (item: GridAlgorithmItem) =>
|
||||||
|
({
|
||||||
|
location: {
|
||||||
|
x: item.xOffset,
|
||||||
|
y: item.yOffset,
|
||||||
|
},
|
||||||
|
size: {
|
||||||
|
width: item.width,
|
||||||
|
height: item.height,
|
||||||
|
},
|
||||||
|
}) satisfies SizedShape;
|
||||||
|
|||||||
@@ -4,4 +4,4 @@ export type { OldmarrApp, OldmarrIntegrationType } from "./app";
|
|||||||
export type { OldmarrWidget, OldmarrWidgetKind } from "./widget";
|
export type { OldmarrWidget, OldmarrWidgetKind } from "./widget";
|
||||||
export { oldmarrWidgetKinds } from "./widget";
|
export { oldmarrWidgetKinds } from "./widget";
|
||||||
export { boardSizes, getBoardSizeName } from "./tile";
|
export { boardSizes, getBoardSizeName } from "./tile";
|
||||||
export type { BoardSize } from "./tile";
|
export type { BoardSize, SizedShape } from "./tile";
|
||||||
|
|||||||
@@ -56,6 +56,8 @@ export const tileBaseSchema = z.object({
|
|||||||
shape: shapeSchema,
|
shape: shapeSchema,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
export type SizedShape = z.infer<typeof sizedShapeSchema>;
|
||||||
|
|
||||||
export const boardSizes = objectKeys(shapeSchema._def.shape());
|
export const boardSizes = objectKeys(shapeSchema._def.shape());
|
||||||
export type BoardSize = (typeof boardSizes)[number];
|
export type BoardSize = (typeof boardSizes)[number];
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user