import { createId } from "@homarr/common"; import { createDbInsertCollectionForTransaction } from "@homarr/db/collection"; import { logger } from "@homarr/log"; import type { BoardSize, OldmarrConfig } from "@homarr/old-schema"; import { boardSizes, getBoardSizeName } from "@homarr/old-schema"; import { fixSectionIssues } from "../../fix-section-issues"; import { OldHomarrImportError } from "../../import-error"; import { mapBoard } from "../../mappers/map-board"; import { mapBreakpoint } from "../../mappers/map-breakpoint"; import { mapColumnCount } from "../../mappers/map-column-count"; import { moveWidgetsAndAppsIfMerge } from "../../move-widgets-and-apps-merge"; import { prepareItems } from "../../prepare/prepare-items"; import type { prepareMultipleImports } from "../../prepare/prepare-multiple"; import { prepareSections } from "../../prepare/prepare-sections"; import type { InitialOldmarrImportSettings } from "../../settings"; export const createBoardInsertCollection = ( { preparedApps, preparedBoards }: Omit, "preparedIntegrations">, settings: InitialOldmarrImportSettings, ) => { const insertCollection = createDbInsertCollectionForTransaction([ "apps", "boards", "layouts", "sections", "items", "itemLayouts", ]); logger.info("Preparing boards for insert collection"); const appsMap = new Map( preparedApps.flatMap(({ ids, ...app }) => { const id = app.existingId ?? createId(); return ids.map((oldId) => [oldId, { id, ...app }] as const); }), ); for (const app of appsMap.values()) { // Skip duplicate apps if (insertCollection.apps.some((appEntry) => appEntry.id === app.id)) { continue; } // Skip apps that already exist in the database if (app.existingId) { continue; } insertCollection.apps.push(app); } if (settings.onlyImportApps) { logger.info( `Skipping boards and sections import due to onlyImportApps setting appCount=${insertCollection.apps.length}`, ); return insertCollection; } logger.debug(`Added apps to board insert collection count=${insertCollection.apps.length}`); preparedBoards.forEach((board) => { if (!hasEnoughItemShapes(board.config)) { throw new OldHomarrImportError( board.config, new Error("Your config contains items without shapes for all board sizes."), ); } const { wrappers, categories, wrapperIdsToMerge } = fixSectionIssues(board.config); const { apps, widgets } = moveWidgetsAndAppsIfMerge(board.config, wrapperIdsToMerge, { ...settings, name: board.name, }); logger.debug(`Fixed issues with sections and item positions fileName=${board.name}`); const mappedBoard = mapBoard(board); logger.debug(`Mapped board fileName=${board.name} boardId=${mappedBoard.id}`); insertCollection.boards.push(mappedBoard); const layoutMapping = boardSizes.reduce( (acc, size) => { acc[size] = createId(); return acc; }, {} as Record, ); insertCollection.layouts.push( ...boardSizes.map((size) => ({ id: layoutMapping[size], boardId: mappedBoard.id, columnCount: mapColumnCount(board.config.settings.customization.gridstack, size), breakpoint: mapBreakpoint(size), name: getBoardSizeName(size), })), ); const preparedSections = prepareSections(mappedBoard.id, { wrappers, categories }); for (const section of preparedSections.values()) { insertCollection.sections.push(section); } logger.debug(`Added sections to board insert collection count=${insertCollection.sections.length}`); 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); }); logger.debug(`Added items to board insert collection count=${insertCollection.items.length}`); }); logger.info( `Board collection prepared boardCount=${insertCollection.boards.length} sectionCount=${insertCollection.sections.length} itemCount=${insertCollection.items.length} appCount=${insertCollection.apps.length}`, ); return insertCollection; }; export const hasEnoughItemShapes = (config: { apps: Pick[]; widgets: Pick[]; }) => { const invalidSizes: BoardSize[] = []; for (const size of boardSizes) { if (invalidSizes.includes(size)) continue; if (config.apps.some((app) => app.shape[size] === undefined)) { invalidSizes.push(size); } if (invalidSizes.includes(size)) continue; if (config.widgets.some((widget) => widget.shape[size] === undefined)) { invalidSizes.push(size); } } return invalidSizes.length <= 2; };