feat(onboarding): enhance integration setup with Docker discovery, URL templating, and API key helpers
Add automatic Docker container discovery during onboarding to pre-select and pre-fill integrations. Introduce base URL templating with subdomain/port modes, API key settings path links, and a curated onboarding list that hides niche integrations (GitHub, npm, Docker Hub, etc.). Prevent duplicate widget seeding and remove the timetable widget from defaults.
This commit is contained in:
18 files changed
+1056
-56
No files matched your search
@@ -1,6 +1,12 @@
|
||||
import { objectEntries } from "@homarr/common";
|
||||
import type { IntegrationKind, WidgetKind } from "@homarr/definitions";
|
||||
import { featuredIntegrations, getIntegrationName, integrationDefs, integrationKinds } from "@homarr/definitions";
|
||||
import {
|
||||
featuredIntegrations,
|
||||
getIntegrationName,
|
||||
hiddenFromOnboarding,
|
||||
integrationDefs,
|
||||
integrationKinds,
|
||||
} from "@homarr/definitions";
|
||||
import { widgetImports } from "@homarr/widgets";
|
||||
|
||||
export const CARD_HEIGHT = 180;
|
||||
@@ -62,9 +68,13 @@ export interface IntegrationGridItem {
|
||||
widgets: WidgetKind[];
|
||||
}
|
||||
|
||||
export const buildSortedIntegrations = (enableMockIntegration: boolean): IntegrationGridItem[] =>
|
||||
export const buildSortedIntegrations = (options: { enableMockIntegration?: boolean; onboarding?: boolean } = {}): IntegrationGridItem[] =>
|
||||
integrationKinds
|
||||
.filter((kind) => enableMockIntegration || kind !== "mock")
|
||||
.filter((kind) => {
|
||||
if (options.onboarding && hiddenFromOnboarding.has(kind)) return false;
|
||||
if (!options.enableMockIntegration && kind === "mock") return false;
|
||||
return true;
|
||||
})
|
||||
.map((kind) => ({
|
||||
kind,
|
||||
name: getIntegrationName(kind),
|
||||
|
||||
@@ -16,18 +16,20 @@ import {
|
||||
} from "./integration-grid-shared";
|
||||
|
||||
interface IntegrationMultiSelectGridProps {
|
||||
selectedKinds: IntegrationKind[];
|
||||
onSelectionChange: (kinds: IntegrationKind[]) => void;
|
||||
initialSelection?: IntegrationKind[];
|
||||
enableMockIntegration?: boolean;
|
||||
onboarding?: boolean;
|
||||
}
|
||||
|
||||
export const IntegrationMultiSelectGrid = ({
|
||||
selectedKinds: selectedKindsArray,
|
||||
onSelectionChange,
|
||||
initialSelection = [],
|
||||
enableMockIntegration = false,
|
||||
onboarding = false,
|
||||
}: IntegrationMultiSelectGridProps) => {
|
||||
const [search, setSearch] = useState("");
|
||||
const [selectedKinds, setSelectedKinds] = useState<Set<IntegrationKind>>(() => new Set(initialSelection));
|
||||
const selectedKinds = useMemo(() => new Set(selectedKindsArray), [selectedKindsArray]);
|
||||
const t = useI18n();
|
||||
|
||||
const toggleKind = useCallback(
|
||||
@@ -38,13 +40,12 @@ export const IntegrationMultiSelectGrid = ({
|
||||
} else {
|
||||
next.add(kind);
|
||||
}
|
||||
setSelectedKinds(next);
|
||||
onSelectionChange(Array.from(next));
|
||||
},
|
||||
[selectedKinds, onSelectionChange],
|
||||
);
|
||||
|
||||
const integrations = useMemo(() => buildSortedIntegrations(enableMockIntegration), [enableMockIntegration]);
|
||||
const integrations = useMemo(() => buildSortedIntegrations({ enableMockIntegration, onboarding }), [enableMockIntegration, onboarding]);
|
||||
const filtered = useMemo(() => filterIntegrations(integrations, search), [integrations, search]);
|
||||
|
||||
return (
|
||||
|
||||
@@ -24,7 +24,7 @@ export const IntegrationSelectGrid = ({ onSelect, enableMockIntegration = false
|
||||
const [search, setSearch] = useState("");
|
||||
const t = useI18n();
|
||||
|
||||
const integrations = useMemo(() => buildSortedIntegrations(enableMockIntegration), [enableMockIntegration]);
|
||||
const integrations = useMemo(() => buildSortedIntegrations({ enableMockIntegration }), [enableMockIntegration]);
|
||||
const filtered = useMemo(() => filterIntegrations(integrations, search), [integrations, search]);
|
||||
|
||||
return (
|
||||
|
||||
Reference in new issue
Block a user