diff --git a/apps/nextjs/src/app/[locale]/init/_steps/integrations/docker-discovery-panel.tsx b/apps/nextjs/src/app/[locale]/init/_steps/integrations/docker-discovery-panel.tsx
new file mode 100644
index 000000000..83320184c
--- /dev/null
+++ b/apps/nextjs/src/app/[locale]/init/_steps/integrations/docker-discovery-panel.tsx
@@ -0,0 +1,152 @@
+"use client";
+
+import { useEffect, useRef, useState } from "react";
+import {
+ Avatar,
+ Badge,
+ Checkbox,
+ Collapse,
+ Divider,
+ Group,
+ Paper,
+ Stack,
+ Text,
+ ThemeIcon,
+ UnstyledButton,
+} from "@mantine/core";
+import { IconChevronDown, IconBrandDocker } from "@tabler/icons-react";
+
+import type { IntegrationKind } from "@homarr/definitions";
+import { getIntegrationName } from "@homarr/definitions";
+import { useScopedI18n } from "@homarr/translation/client";
+import { IntegrationAvatar } from "@homarr/ui";
+
+export interface DiscoveredIntegration {
+ containerId: string;
+ containerName: string;
+ kind: IntegrationKind;
+ suggestedUrl: string;
+ publishedPort: number | null;
+ iconUrl: string | null;
+}
+
+export interface DiscoveredApp {
+ containerId: string;
+ containerName: string;
+ suggestedUrl: string;
+ iconUrl: string | null;
+}
+
+interface DockerDiscoveryIndicatorProps {
+ integrations: DiscoveredIntegration[];
+ apps: DiscoveredApp[];
+ appsEnabled: boolean;
+ onToggleAllApps: (checked: boolean) => void;
+}
+
+export const DockerDiscoveryIndicator = ({
+ integrations,
+ apps,
+ appsEnabled,
+ onToggleAllApps,
+}: DockerDiscoveryIndicatorProps) => {
+ const hasApps = apps.length > 0;
+ const [expanded, setExpanded] = useState(false);
+
+ const expandedOnce = useRef(false);
+ useEffect(() => {
+ if (hasApps && !expandedOnce.current) {
+ expandedOnce.current = true;
+ setExpanded(true);
+ }
+ }, [hasApps]);
+ const t = useScopedI18n("init.step.integrations.docker");
+ const totalCount = integrations.length + apps.length;
+
+ if (totalCount === 0) return null;
+
+ return (
+
+ setExpanded((v) => !v)} w="100%">
+
+
+
+
+
+
+
+ {t("detected", { count: String(totalCount) })}
+
+
+ {t("detectedBreakdown", {
+ integrations: String(integrations.length),
+ apps: String(apps.length),
+ })}
+
+
+
+
+
+
+
+
+
+ {integrations.map((integration) => (
+
+
+
+ {integration.containerName}
+
+
+ {getIntegrationName(integration.kind)}
+
+
+ ))}
+
+ {hasApps && (
+ <>
+ {integrations.length > 0 && }
+ onToggleAllApps(!appsEnabled)}
+ styles={{ label: { fontSize: "var(--mantine-font-size-xs)" } }}
+ />
+ {appsEnabled && apps.map((app) => (
+
+
+ {app.containerName.at(0)?.toUpperCase()}
+
+
+ {app.containerName}
+
+
+ ))}
+ >
+ )}
+
+
+
+ );
+};
diff --git a/apps/nextjs/src/app/[locale]/init/_steps/integrations/init-integrations.tsx b/apps/nextjs/src/app/[locale]/init/_steps/integrations/init-integrations.tsx
index b0caa7189..f6302e5ab 100644
--- a/apps/nextjs/src/app/[locale]/init/_steps/integrations/init-integrations.tsx
+++ b/apps/nextjs/src/app/[locale]/init/_steps/integrations/init-integrations.tsx
@@ -1,37 +1,118 @@
"use client";
-import { useCallback, useState } from "react";
+import { useCallback, useEffect, useRef, useState } from "react";
import { useRouter } from "next/navigation";
-import { Button, Card, Center, Group, Loader, Progress, Stack, Text } from "@mantine/core";
-import { IconArrowRight } from "@tabler/icons-react";
+import {
+ ActionIcon,
+ Button,
+ Card,
+ Center,
+ Collapse,
+ Group,
+ Loader,
+ Progress,
+ SegmentedControl,
+ Stack,
+ Text,
+ TextInput,
+ Tooltip,
+} from "@mantine/core";
+import { useDisclosure } from "@mantine/hooks";
+import { IconArrowRight, IconSettings } from "@tabler/icons-react";
import { clientApi } from "@homarr/api/client";
import type { IntegrationKind } from "@homarr/definitions";
-import { getIntegrationName } from "@homarr/definitions";
+import { buildIntegrationUrl, getIntegrationName } from "@homarr/definitions";
+import type { UrlTemplateMode } from "@homarr/definitions";
import { useScopedI18n } from "@homarr/translation/client";
import { IntegrationAvatar } from "@homarr/ui";
import { NewIntegrationForm } from "~/app/[locale]/manage/integrations/new/_integration-new-form";
import { IntegrationMultiSelectGrid } from "~/components/integration/integration-multi-select-grid";
+import { DockerDiscoveryIndicator } from "./docker-discovery-panel";
+
type Phase = "select" | "configure" | "done";
+interface IntegrationDraft {
+ kind: IntegrationKind;
+ initialUrl: string;
+ initialName?: string;
+ dockerPort?: number | null;
+ source: "manual" | "docker";
+}
+
const CARD_WIDTH = 64 * 16;
export const InitIntegrations = () => {
const [phase, setPhase] = useState("select");
+ const [drafts, setDrafts] = useState