fix: unable to select integration on board page (#450)
This commit is contained in:
@@ -13,6 +13,7 @@ import type { IntegrationKind, WidgetKind } from "@homarr/definitions";
|
|||||||
import { useModalAction } from "@homarr/modals";
|
import { useModalAction } from "@homarr/modals";
|
||||||
import { showSuccessNotification } from "@homarr/notifications";
|
import { showSuccessNotification } from "@homarr/notifications";
|
||||||
import { useScopedI18n } from "@homarr/translation/client";
|
import { useScopedI18n } from "@homarr/translation/client";
|
||||||
|
import type { BoardItemIntegration } from "@homarr/validation";
|
||||||
import {
|
import {
|
||||||
loadWidgetDynamic,
|
loadWidgetDynamic,
|
||||||
reduceWidgetOptionsWithDefaultValues,
|
reduceWidgetOptionsWithDefaultValues,
|
||||||
@@ -53,7 +54,7 @@ export const WidgetPreviewPageContent = ({
|
|||||||
});
|
});
|
||||||
const [state, setState] = useState<{
|
const [state, setState] = useState<{
|
||||||
options: Record<string, unknown>;
|
options: Record<string, unknown>;
|
||||||
integrations: string[];
|
integrations: BoardItemIntegration[];
|
||||||
}>({
|
}>({
|
||||||
options: reduceWidgetOptionsWithDefaultValues(kind, {}),
|
options: reduceWidgetOptionsWithDefaultValues(kind, {}),
|
||||||
integrations: [],
|
integrations: [],
|
||||||
@@ -104,8 +105,10 @@ export const WidgetPreviewPageContent = ({
|
|||||||
<Comp
|
<Comp
|
||||||
options={state.options as never}
|
options={state.options as never}
|
||||||
integrations={state.integrations.map(
|
integrations={state.integrations.map(
|
||||||
(id) =>
|
(stateIntegration) =>
|
||||||
integrationData.find((integration) => integration.id === id)!,
|
integrationData.find(
|
||||||
|
(integration) => integration.id === stateIntegration.id,
|
||||||
|
)!,
|
||||||
)}
|
)}
|
||||||
width={dimensions.width}
|
width={dimensions.width}
|
||||||
height={dimensions.height}
|
height={dimensions.height}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import { useCallback } from "react";
|
|||||||
|
|
||||||
import { createId } from "@homarr/db/client";
|
import { createId } from "@homarr/db/client";
|
||||||
import type { WidgetKind } from "@homarr/definitions";
|
import type { WidgetKind } from "@homarr/definitions";
|
||||||
|
import type { BoardItemIntegration } from "@homarr/validation";
|
||||||
|
|
||||||
import type { EmptySection, Item } from "~/app/[locale]/boards/_types";
|
import type { EmptySection, Item } from "~/app/[locale]/boards/_types";
|
||||||
import { useUpdateBoard } from "~/app/[locale]/boards/(content)/_client";
|
import { useUpdateBoard } from "~/app/[locale]/boards/(content)/_client";
|
||||||
@@ -30,6 +31,11 @@ interface UpdateItemOptions {
|
|||||||
newOptions: Record<string, unknown>;
|
newOptions: Record<string, unknown>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface UpdateItemIntegrations {
|
||||||
|
itemId: string;
|
||||||
|
newIntegrations: BoardItemIntegration[];
|
||||||
|
}
|
||||||
|
|
||||||
interface CreateItem {
|
interface CreateItem {
|
||||||
kind: WidgetKind;
|
kind: WidgetKind;
|
||||||
}
|
}
|
||||||
@@ -105,6 +111,36 @@ export const useItemActions = () => {
|
|||||||
[updateBoard],
|
[updateBoard],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const updateItemIntegrations = useCallback(
|
||||||
|
({ itemId, newIntegrations }: UpdateItemIntegrations) => {
|
||||||
|
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 moving
|
||||||
|
if (item.id !== itemId) return item;
|
||||||
|
return {
|
||||||
|
...item,
|
||||||
|
...("integrations" in item
|
||||||
|
? { integrations: newIntegrations }
|
||||||
|
: {}),
|
||||||
|
};
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
});
|
||||||
|
},
|
||||||
|
[updateBoard],
|
||||||
|
);
|
||||||
|
|
||||||
const moveAndResizeItem = useCallback(
|
const moveAndResizeItem = useCallback(
|
||||||
({ itemId, ...positionProps }: MoveAndResizeItem) => {
|
({ itemId, ...positionProps }: MoveAndResizeItem) => {
|
||||||
updateBoard((previous) => ({
|
updateBoard((previous) => ({
|
||||||
@@ -200,6 +236,7 @@ export const useItemActions = () => {
|
|||||||
moveItemToSection,
|
moveItemToSection,
|
||||||
removeItem,
|
removeItem,
|
||||||
updateItemOptions,
|
updateItemOptions,
|
||||||
|
updateItemIntegrations,
|
||||||
createItem,
|
createItem,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
/* eslint-disable react/no-unknown-property */
|
/* eslint-disable react/no-unknown-property */
|
||||||
// Ignored because of gridstack attributes
|
// Ignored because of gridstack attributes
|
||||||
|
|
||||||
|
import { useMemo } from "react";
|
||||||
import type { RefObject } from "react";
|
import type { RefObject } from "react";
|
||||||
import { ActionIcon, Card, Menu } from "@mantine/core";
|
import { ActionIcon, Card, Menu } from "@mantine/core";
|
||||||
import { useElementSize } from "@mantine/hooks";
|
import { useElementSize } from "@mantine/hooks";
|
||||||
@@ -13,6 +14,7 @@ import {
|
|||||||
import combineClasses from "clsx";
|
import combineClasses from "clsx";
|
||||||
import { useAtomValue } from "jotai";
|
import { useAtomValue } from "jotai";
|
||||||
|
|
||||||
|
import { clientApi } from "@homarr/api/client";
|
||||||
import { useConfirmModal, useModalAction } from "@homarr/modals";
|
import { useConfirmModal, useModalAction } from "@homarr/modals";
|
||||||
import { useScopedI18n } from "@homarr/translation/client";
|
import { useScopedI18n } from "@homarr/translation/client";
|
||||||
import {
|
import {
|
||||||
@@ -20,6 +22,7 @@ import {
|
|||||||
reduceWidgetOptionsWithDefaultValues,
|
reduceWidgetOptionsWithDefaultValues,
|
||||||
useServerDataFor,
|
useServerDataFor,
|
||||||
WidgetEditModal,
|
WidgetEditModal,
|
||||||
|
widgetImports,
|
||||||
} from "@homarr/widgets";
|
} from "@homarr/widgets";
|
||||||
|
|
||||||
import type { Item } from "~/app/[locale]/boards/_types";
|
import type { Item } from "~/app/[locale]/boards/_types";
|
||||||
@@ -116,25 +119,42 @@ const ItemMenu = ({ offset, item }: { offset: number; item: Item }) => {
|
|||||||
const { openModal } = useModalAction(WidgetEditModal);
|
const { openModal } = useModalAction(WidgetEditModal);
|
||||||
const { openConfirmModal } = useConfirmModal();
|
const { openConfirmModal } = useConfirmModal();
|
||||||
const isEditMode = useAtomValue(editModeAtom);
|
const isEditMode = useAtomValue(editModeAtom);
|
||||||
const { updateItemOptions, removeItem } = useItemActions();
|
const { updateItemOptions, updateItemIntegrations, removeItem } =
|
||||||
|
useItemActions();
|
||||||
|
const { data: integrationData, isPending } =
|
||||||
|
clientApi.integration.all.useQuery();
|
||||||
|
const currentDefinition = useMemo(
|
||||||
|
() => widgetImports[item.kind].definition,
|
||||||
|
[item.kind],
|
||||||
|
);
|
||||||
|
|
||||||
if (!isEditMode) return null;
|
if (!isEditMode || isPending) return null;
|
||||||
|
|
||||||
const openEditModal = () => {
|
const openEditModal = () => {
|
||||||
openModal({
|
openModal({
|
||||||
kind: item.kind,
|
kind: item.kind,
|
||||||
value: {
|
value: {
|
||||||
options: item.options,
|
options: item.options,
|
||||||
integrations: item.integrations.map(({ id }) => id),
|
integrations: item.integrations,
|
||||||
},
|
},
|
||||||
onSuccessfulEdit: ({ options, integrations: _ }) => {
|
onSuccessfulEdit: ({ options, integrations }) => {
|
||||||
updateItemOptions({
|
updateItemOptions({
|
||||||
itemId: item.id,
|
itemId: item.id,
|
||||||
newOptions: options,
|
newOptions: options,
|
||||||
});
|
});
|
||||||
|
updateItemIntegrations({
|
||||||
|
itemId: item.id,
|
||||||
|
newIntegrations: integrations,
|
||||||
|
});
|
||||||
},
|
},
|
||||||
integrationData: [],
|
integrationData: (integrationData ?? []).filter(
|
||||||
integrationSupport: false,
|
(integration) =>
|
||||||
|
"supportedIntegrations" in currentDefinition &&
|
||||||
|
(currentDefinition.supportedIntegrations as string[]).some(
|
||||||
|
(kind) => kind === integration.kind,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
integrationSupport: "supportedIntegrations" in currentDefinition,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -18,4 +18,8 @@ export const validation = {
|
|||||||
icons: iconsSchemas,
|
icons: iconsSchemas,
|
||||||
};
|
};
|
||||||
|
|
||||||
export { createSectionSchema, sharedItemSchema } from "./shared";
|
export {
|
||||||
|
createSectionSchema,
|
||||||
|
sharedItemSchema,
|
||||||
|
type BoardItemIntegration,
|
||||||
|
} from "./shared";
|
||||||
|
|||||||
@@ -11,6 +11,8 @@ export const integrationSchema = z.object({
|
|||||||
url: z.string(),
|
url: z.string(),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
export type BoardItemIntegration = z.infer<typeof integrationSchema>;
|
||||||
|
|
||||||
export const sharedItemSchema = z.object({
|
export const sharedItemSchema = z.object({
|
||||||
id: z.string(),
|
id: z.string(),
|
||||||
xOffset: z.number(),
|
xOffset: z.number(),
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import { Button, Group, Stack } from "@mantine/core";
|
|||||||
import type { WidgetKind } from "@homarr/definitions";
|
import type { WidgetKind } from "@homarr/definitions";
|
||||||
import { createModal } from "@homarr/modals";
|
import { createModal } from "@homarr/modals";
|
||||||
import { useI18n } from "@homarr/translation/client";
|
import { useI18n } from "@homarr/translation/client";
|
||||||
|
import type { BoardItemIntegration } from "@homarr/validation";
|
||||||
|
|
||||||
import { widgetImports } from "..";
|
import { widgetImports } from "..";
|
||||||
import { getInputForType } from "../_inputs";
|
import { getInputForType } from "../_inputs";
|
||||||
@@ -15,7 +16,7 @@ import { WidgetIntegrationSelect } from "../widget-integration-select";
|
|||||||
|
|
||||||
export interface WidgetEditModalState {
|
export interface WidgetEditModalState {
|
||||||
options: Record<string, unknown>;
|
options: Record<string, unknown>;
|
||||||
integrations: string[];
|
integrations: BoardItemIntegration[];
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ModalProps<TSort extends WidgetKind> {
|
interface ModalProps<TSort extends WidgetKind> {
|
||||||
|
|||||||
Reference in New Issue
Block a user