merge: stack widget modernization on dnd kit

This commit is contained in:
Thomas Camlong committed 2026-08-08 20:40:26 +02:00
commit 9edeba5cd2
940 files changed
+104475 -33649

No files matched your search

@@ -15,11 +15,11 @@ import type { SettingsContextProps } from "@homarr/settings/creator";
import { useI18n } from "@homarr/translation/client";
import { zodErrorMap } from "@homarr/validation/form/i18n";
import { widgetImports } from "..";
import { getInputForType } from "../_inputs";
import { FormProvider, useForm } from "../_inputs/form";
import type { BoardItemAdvancedOptions } from "../../../validation/src/shared";
import type { OptionsBuilderResult } from "../options";
import type { WidgetDefinition } from "../definition";
import { OPTIONS_SUPER_REFINE } from "../options";
import type { IntegrationSelectOption } from "../widget-integration-select";
import { WidgetIntegrationSelect } from "../widget-integration-select";
@@ -33,8 +33,9 @@ export interface WidgetEditModalState {
advancedOptions: BoardItemAdvancedOptions;
}
interface ModalProps<TSort extends WidgetKind> {
export interface WidgetEditModalProps<TSort extends WidgetKind> {
kind: TSort;
definition: WidgetDefinition;
value: WidgetEditModalState;
onSuccessfulEdit: (value: WidgetEditModalState) => void;
integrationData: IntegrationSelectOption[];
@@ -45,7 +46,7 @@ interface ModalProps<TSort extends WidgetKind> {
appId?: string;
}
export const WidgetEditModal = createModal<ModalProps<WidgetKind>>(({ actions, innerProps }) => {
export const WidgetEditModal = createModal<WidgetEditModalProps<WidgetKind>>(({ actions, innerProps }) => {
const t = useI18n();
const board = useOptionalBoard();
const { data: session } = useSession();
@@ -56,7 +57,7 @@ export const WidgetEditModal = createModal<ModalProps<WidgetKind>>(({ actions, i
z.config({
customError: zodErrorMap(t),
});
const { definition } = widgetImports[innerProps.kind];
const { definition } = innerProps;
const options = definition.createOptions(innerProps.settings) as Record<string, OptionsBuilderResult[string]>;
const optionsSuperRefine = (options as Record<symbol, unknown>)[OPTIONS_SUPER_REFINE] as
| ((data: Record<string, unknown>, ctx: z.RefinementCtx) => void)
@@ -95,6 +96,7 @@ export const WidgetEditModal = createModal<ModalProps<WidgetKind>>(({ actions, i
const { openModal } = useModalAction(WidgetAdvancedOptionsModal);
const canModifyApps = session?.user.permissions.includes("app-modify-all") ?? false;
const canConfigureWidget = innerProps.kind !== "customApi" || (session?.user.permissions.includes("admin") ?? false);
const appId = innerProps.appId;
const showAppTab = innerProps.kind === "app" && canModifyApps && Boolean(appId);
@@ -123,44 +125,42 @@ export const WidgetEditModal = createModal<ModalProps<WidgetKind>>(({ actions, i
const widgetFormContent = (
<Stack>
{innerProps.integrationSupport && (
{canConfigureWidget && innerProps.integrationSupport && (
<WidgetIntegrationSelect
label={t("item.edit.field.integrations.label")}
data={innerProps.integrationData}
canSelectMultiple={
((widgetImports[innerProps.kind].definition as { maxIntegrations?: number }).maxIntegrations ?? Infinity) >
1
}
canSelectMultiple={((definition as { maxIntegrations?: number }).maxIntegrations ?? Infinity) > 1}
{...form.getInputProps("integrationIds")}
/>
)}
{Object.entries(options).map(([key, value]) => {
const Input = getInputForType(value.type);
{canConfigureWidget &&
Object.entries(options).map(([key, value]) => {
const Input = getInputForType(value.type);
if (
!Input ||
value.shouldHide?.(
form.values.options as never,
innerProps.integrationData
.filter(({ id }) => form.values.integrationIds.includes(id))
.map(({ kind }) => kind),
)
) {
return null;
}
if (
!Input ||
value.shouldHide?.(
form.values.options as never,
innerProps.integrationData
.filter(({ id }) => form.values.integrationIds.includes(id))
.map(({ kind }) => kind),
)
) {
return null;
}
return (
<Input
key={key}
kind={innerProps.kind}
property={key}
options={value as never}
initialOptions={innerProps.value.options}
itemId={innerProps.itemId}
boardId={innerProps.boardId ?? board?.id}
/>
);
})}
return (
<Input
key={key}
kind={innerProps.kind}
property={key}
options={value as never}
initialOptions={innerProps.value.options}
itemId={innerProps.itemId}
boardId={innerProps.boardId ?? board?.id}
/>
);
})}
{showAppTab ? (
<Button
variant="subtle"