When adding a widget from the "Choose item to add" modal, the widget edit modal now opens immediately after placement, allowing the user to configure options and integrations before the widget renders. All available integrations for the widget are selected by default.
75 lines
2.0 KiB
TypeScript
75 lines
2.0 KiB
TypeScript
import { getBoardLayouts } from "@homarr/boards/context";
|
|
import { createId } from "@homarr/common";
|
|
import type { Modify } from "@homarr/common/types";
|
|
import type { WidgetKind } from "@homarr/definitions";
|
|
|
|
import type { Board, EmptySection, Item, ItemLayout } from "~/app/[locale]/boards/_types";
|
|
import { getFirstEmptyPosition } from "./empty-position";
|
|
import { getSectionElements } from "./section-elements";
|
|
|
|
export interface CreateItemInput {
|
|
id?: string;
|
|
kind: WidgetKind;
|
|
options?: Record<string, unknown>;
|
|
integrationIds?: string[];
|
|
}
|
|
|
|
export const createItemCallback =
|
|
({ id, kind, options = {}, integrationIds = [] }: CreateItemInput) =>
|
|
(previous: Board): Board => {
|
|
const firstSection = previous.sections
|
|
.filter((section): section is EmptySection => section.kind === "empty")
|
|
.sort((sectionA, sectionB) => sectionA.yOffset - sectionB.yOffset)
|
|
.at(0);
|
|
|
|
if (!firstSection) return previous;
|
|
|
|
const widget = {
|
|
id: id ?? createId(),
|
|
kind,
|
|
options,
|
|
layouts: createItemLayouts(previous, firstSection),
|
|
integrationIds,
|
|
advancedOptions: {
|
|
title: null,
|
|
customCssClasses: [],
|
|
borderColor: "",
|
|
},
|
|
} satisfies Modify<
|
|
Item,
|
|
{
|
|
kind: WidgetKind;
|
|
}
|
|
>;
|
|
|
|
return {
|
|
...previous,
|
|
items: previous.items.concat(widget),
|
|
};
|
|
};
|
|
|
|
const createItemLayouts = (board: Board, currentSection: EmptySection): ItemLayout[] => {
|
|
const layouts = getBoardLayouts(board);
|
|
|
|
return layouts.map((layoutId) => {
|
|
const boardLayout = board.layouts.find((layout) => layout.id === layoutId);
|
|
const elements = getSectionElements(board, { sectionId: currentSection.id, layoutId });
|
|
|
|
const emptyPosition = boardLayout
|
|
? getFirstEmptyPosition(elements, boardLayout.columnCount)
|
|
: { xOffset: 0, yOffset: 0 };
|
|
|
|
if (!emptyPosition) {
|
|
throw new Error("Your board is full");
|
|
}
|
|
|
|
return {
|
|
width: 1,
|
|
height: 1,
|
|
...emptyPosition,
|
|
sectionId: currentSection.id,
|
|
layoutId,
|
|
};
|
|
});
|
|
};
|