Skip to content

Commit

Permalink
fix(import): autofix missing sizes of items with grid-algorithm
Browse files Browse the repository at this point in the history
  • Loading branch information
Meierschlumpf committed Mar 6, 2025
1 parent 3403579 commit 7038fba
Show file tree
Hide file tree
Showing 6 changed files with 115 additions and 14 deletions.
14 changes: 12 additions & 2 deletions packages/old-import/src/import/collections/board-collection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ export const createBoardInsertCollection = (
...boardSizes.map((size) => ({
id: layoutMapping[size],
boardId: mappedBoard.id,
columnCount: mapColumnCount(board.config, size),
columnCount: mapColumnCount(board.config.settings.customization.gridstack, size),
breakpoint: mapBreakpoint(size),
name: getBoardSizeName(size),
})),
Expand All @@ -94,7 +94,17 @@ export const createBoardInsertCollection = (
}
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 }) => {
insertCollection.items.push(item);
insertCollection.itemLayouts.push(...layouts);
Expand Down
11 changes: 7 additions & 4 deletions packages/old-import/src/mappers/map-column-count.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
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) {
case "lg":
return old.settings.customization.gridstack.columnCountLarge;
return gridstackSettings.columnCountLarge;
case "md":
return old.settings.customization.gridstack.columnCountMedium;
return gridstackSettings.columnCountMedium;
case "sm":
return old.settings.customization.gridstack.columnCountSmall;
return gridstackSettings.columnCountSmall;
default:
return 10;
}
Expand Down
4 changes: 2 additions & 2 deletions packages/old-import/src/move-widgets-and-apps-merge.ts
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ const moveWidgetsAndAppsInLeftSidebar = (
offset: number,
screenSize: BoardSize,
) => {
const columnCount = mapColumnCount(old, screenSize);
const columnCount = mapColumnCount(old.settings.customization.gridstack, screenSize);
let requiredHeight = updateItems({
// This should work as the reference of the items did not change, only the array reference did
items: [...old.widgets, ...old.apps],
Expand Down Expand Up @@ -211,7 +211,7 @@ const moveWidgetsAndAppsInRightSidebar = (
offset: number,
screenSize: BoardSize,
) => {
const columnCount = mapColumnCount(old, screenSize);
const columnCount = mapColumnCount(old.settings.customization.gridstack, screenSize);
const xOffsetDelta = Math.max(columnCount - 2, 0);
const requiredHeight = updateItems({
// This should work as the reference of the items did not change, only the array reference did
Expand Down
96 changes: 91 additions & 5 deletions packages/old-import/src/prepare/prepare-items.ts
Original file line number Diff line number Diff line change
@@ -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";

export const prepareItems = (
{ apps, widgets }: Pick<OldmarrConfig, "apps" | "widgets">,
{ apps, widgets, settings }: Pick<OldmarrConfig, "apps" | "widgets" | "settings">,
appsMap: Map<string, { id: string }>,
sectionMap: Map<string, { id: string }>,
layoutMap: Record<BoardSize, 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))
.concat(apps.map((app) => mapApp(app, appsMap, sectionMap, layoutMap, boardId)))
.concat(localApps.map((app) => mapApp(app, appsMap, sectionMap, layoutMap, boardId)))
.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;
2 changes: 1 addition & 1 deletion packages/old-schema/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,4 @@ export type { OldmarrApp, OldmarrIntegrationType } from "./app";
export type { OldmarrWidget, OldmarrWidgetKind } from "./widget";
export { oldmarrWidgetKinds } from "./widget";
export { boardSizes, getBoardSizeName } from "./tile";
export type { BoardSize } from "./tile";
export type { BoardSize, SizedShape } from "./tile";
2 changes: 2 additions & 0 deletions packages/old-schema/src/tile.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,8 @@ export const tileBaseSchema = z.object({
shape: shapeSchema,
});

export type SizedShape = z.infer<typeof sizedShapeSchema>;

export const boardSizes = objectKeys(shapeSchema._def.shape());
export type BoardSize = (typeof boardSizes)[number];

Expand Down

0 comments on commit 7038fba

Please # to comment.