feat(board): implement advanced add app modal with live preview and remove today widget

This commit is contained in:
Thomas Camlong committed 2026-08-20 23:42:24 +02:00
1 parent 7e8c139590
commit 829f628fec
32 files changed
+2408 -1099

No files matched your search

@@ -1,20 +0,0 @@
.action {
opacity: 0;
transition: opacity 150ms ease;
}
.card:hover .action,
.card:focus-within .action {
opacity: 1;
}
@media (hover: none), (pointer: coarse) {
.action {
opacity: 1;
}
}
@media (prefers-reduced-motion: reduce) {
.action {
transition: none;
}
}
File diff suppressed because it is too large. Load diff
@@ -1,9 +1,10 @@
"use client";
import { useState } from "react";
import { useEffect, useState } from "react";
import { Group, ScrollArea, Title, UnstyledButton } from "@mantine/core";
import { IconArrowLeft, IconX } from "@tabler/icons-react";
import { clientApi } from "@homarr/api/client";
import type { IntegrationKind } from "@homarr/definitions";
import { getIntegrationName } from "@homarr/definitions";
import { createModal, modalSizeSelect, useModalAction } from "@homarr/modals";
@@ -27,9 +28,28 @@ interface IntegrationSelectModalProps {
export const IntegrationSelectModal = createModal<IntegrationSelectModalProps>(({ actions, innerProps }) => {
const t = useI18n();
const [step, setStep] = useState<"select" | "form">(innerProps.initialKind ? "form" : "select");
const [selectedKind, setSelectedKind] = useState<IntegrationKind | null>(innerProps.initialKind ?? null);
const directKind =
innerProps.initialKind ?? (innerProps.allowedKinds?.length === 1 ? innerProps.allowedKinds[0] : null);
const isDirectForm = Boolean(directKind);
const [step, setStep] = useState<"select" | "form">(isDirectForm ? "form" : "select");
const [selectedKind, setSelectedKind] = useState<IntegrationKind | null>(directKind ?? null);
const { openModal: openCompletionModal } = useModalAction(IntegrationCompletionModal);
const { data: integrationData } = clientApi.integration.all.useQuery();
useEffect(() => {
if (step === "form" && !isDirectForm) {
actions.setCloseInterceptor?.(() => {
setStep("select");
setSelectedKind(null);
return false;
});
} else {
actions.setCloseInterceptor?.(null);
}
return () => {
actions.setCloseInterceptor?.(null);
};
}, [step, isDirectForm, actions]);
const handleSelect = (kind: IntegrationKind) => {
setSelectedKind(kind);
@@ -40,7 +60,7 @@ export const IntegrationSelectModal = createModal<IntegrationSelectModalProps>((
setStep("select");
setSelectedKind(null);
};
const handleFormBack = innerProps.initialKind ? actions.closeModal : handleBack;
const handleFormBack = isDirectForm ? actions.closeModal : handleBack;
const handleSuccess = (result?: CreatedIntegrationResult) => {
actions.closeModal();
@@ -52,12 +72,8 @@ export const IntegrationSelectModal = createModal<IntegrationSelectModalProps>((
};
if (step === "form" && selectedKind) {
let HeaderIcon = IconArrowLeft;
let headerLabel = t("common.action.previous");
if (innerProps.initialKind) {
HeaderIcon = IconX;
headerLabel = t("common.action.close");
}
const HeaderIcon = isDirectForm ? IconX : IconArrowLeft;
const headerLabel = isDirectForm ? t("common.action.close") : t("common.action.previous");
return (
<ScrollArea.Autosize mah="80vh">
@@ -84,6 +100,7 @@ export const IntegrationSelectModal = createModal<IntegrationSelectModalProps>((
onSelect={handleSelect}
enableMockIntegration={innerProps.enableMockIntegration}
allowedKinds={innerProps.allowedKinds}
integrationData={integrationData}
/>
);
}).withOptions({