feat: add custom css for board and custom classes in advanced options for items (#512)

* feat: add custom css for board and custom classes in advanced options for items

* chore: add mysql migration

* fix: test not working

* fix: format issues

* fix: typecheck issue

* fix: build issue

* chore: add missing translations

* fix: merge issues related to migrations

* fix: format issues

* fix: merge issue with migration

* fix: format issue
This commit is contained in:
Meier Lukas
2024-05-19 23:01:26 +02:00
committed by GitHub
parent f1b1ec59ec
commit 26b1c4a319
35 changed files with 3080 additions and 97 deletions

View File

@@ -2,7 +2,7 @@ import { useCallback } from "react";
import { createId } from "@homarr/db/client";
import type { WidgetKind } from "@homarr/definitions";
import type { BoardItemIntegration } from "@homarr/validation";
import type { BoardItemAdvancedOptions, BoardItemIntegration } from "@homarr/validation";
import type { EmptySection, Item } from "~/app/[locale]/boards/_types";
import { useUpdateBoard } from "~/app/[locale]/boards/(content)/_client";
@@ -31,6 +31,11 @@ interface UpdateItemOptions {
newOptions: Record<string, unknown>;
}
interface UpdateItemAdvancedOptions {
itemId: string;
newAdvancedOptions: BoardItemAdvancedOptions;
}
interface UpdateItemIntegrations {
itemId: string;
newIntegrations: BoardItemIntegration[];
@@ -59,6 +64,9 @@ export const useItemActions = () => {
width: 1,
height: 1,
integrations: [],
advancedOptions: {
customCssClasses: [],
},
} satisfies Omit<Item, "kind" | "yOffset" | "xOffset"> & {
kind: WidgetKind;
};
@@ -91,7 +99,7 @@ export const useItemActions = () => {
return {
...section,
items: section.items.map((item) => {
// Return same item if item is not the one we're moving
// Return same item if item is not the one we're changing
if (item.id !== itemId) return item;
return {
...item,
@@ -106,6 +114,33 @@ export const useItemActions = () => {
[updateBoard],
);
const updateItemAdvancedOptions = useCallback(
({ itemId, newAdvancedOptions }: UpdateItemAdvancedOptions) => {
updateBoard((previous) => {
if (!previous) return previous;
return {
...previous,
sections: previous.sections.map((section) => {
// Return same section if item is not in it
if (!section.items.some((item) => item.id === itemId)) return section;
return {
...section,
items: section.items.map((item) => {
// Return same item if item is not the one we're changing
if (item.id !== itemId) return item;
return {
...item,
advancedOptions: newAdvancedOptions,
};
}),
};
}),
};
});
},
[updateBoard],
);
const updateItemIntegrations = useCallback(
({ itemId, newIntegrations }: UpdateItemIntegrations) => {
updateBoard((previous) => {
@@ -224,6 +259,7 @@ export const useItemActions = () => {
moveItemToSection,
removeItem,
updateItemOptions,
updateItemAdvancedOptions,
updateItemIntegrations,
createItem,
};

View File

@@ -70,7 +70,11 @@ const BoardItem = ({ refs, item, opacity }: ItemProps) => {
>
<Card
ref={ref}
className={combineClasses(classes.itemCard, "grid-stack-item-content")}
className={combineClasses(
classes.itemCard,
"grid-stack-item-content",
item.advancedOptions.customCssClasses.join(" "),
)}
withBorder
styles={{
root: {
@@ -123,7 +127,7 @@ const ItemMenu = ({ offset, item }: { offset: number; item: Item }) => {
const { openModal } = useModalAction(WidgetEditModal);
const { openConfirmModal } = useConfirmModal();
const isEditMode = useAtomValue(editModeAtom);
const { updateItemOptions, updateItemIntegrations, removeItem } = useItemActions();
const { updateItemOptions, updateItemAdvancedOptions, updateItemIntegrations, removeItem } = useItemActions();
const { data: integrationData, isPending } = clientApi.integration.all.useQuery();
const currentDefinition = useMemo(() => widgetImports[item.kind].definition, [item.kind]);
@@ -133,14 +137,19 @@ const ItemMenu = ({ offset, item }: { offset: number; item: Item }) => {
openModal({
kind: item.kind,
value: {
advancedOptions: item.advancedOptions,
options: item.options,
integrations: item.integrations,
},
onSuccessfulEdit: ({ options, integrations }) => {
onSuccessfulEdit: ({ options, integrations, advancedOptions }) => {
updateItemOptions({
itemId: item.id,
newOptions: options,
});
updateItemAdvancedOptions({
itemId: item.id,
newAdvancedOptions: advancedOptions,
});
updateItemIntegrations({
itemId: item.id,
newIntegrations: integrations,