diff --git a/apps/nextjs/src/app/[locale]/manage/apps/page.tsx b/apps/nextjs/src/app/[locale]/manage/apps/page.tsx
index 2029fbafa..8dd13774b 100644
--- a/apps/nextjs/src/app/[locale]/manage/apps/page.tsx
+++ b/apps/nextjs/src/app/[locale]/manage/apps/page.tsx
@@ -1,7 +1,7 @@
import Link from "next/link";
import { redirect } from "next/navigation";
import { ActionIcon, ActionIconGroup, Anchor, Avatar, Card, Group, Stack, Text, Title } from "@mantine/core";
-import { IconApps, IconPencil } from "@tabler/icons-react";
+import { IconBox, IconPencil } from "@tabler/icons-react";
import type { RouterOutputs } from "@homarr/api";
import { api } from "@homarr/api/server";
@@ -12,6 +12,7 @@ import { getI18n, getScopedI18n } from "@homarr/translation/server";
import { ManageContainer } from "~/components/manage/manage-container";
import { MobileAffixButton } from "~/components/manage/mobile-affix-button";
import { DynamicBreadcrumb } from "~/components/navigation/dynamic-breadcrumb";
+import { NoResults } from "~/components/no-results";
import { AppDeleteButton } from "./_app-delete-button";
export default async function AppsPage() {
@@ -113,16 +114,14 @@ const AppNoResults = async () => {
const session = await auth();
return (
-
-
-
-
- {t("app.page.list.noResults.title")}
-
- {session?.user.permissions.includes("app-create") && (
- {t("app.page.list.noResults.action")}
- )}
-
-
+
);
};
diff --git a/apps/nextjs/src/app/[locale]/manage/integrations/page.tsx b/apps/nextjs/src/app/[locale]/manage/integrations/page.tsx
index a600effed..853630698 100644
--- a/apps/nextjs/src/app/[locale]/manage/integrations/page.tsx
+++ b/apps/nextjs/src/app/[locale]/manage/integrations/page.tsx
@@ -27,7 +27,7 @@ import {
Text,
Title,
} from "@mantine/core";
-import { IconChevronDown, IconChevronUp, IconPencil } from "@tabler/icons-react";
+import { IconChevronDown, IconChevronUp, IconPencil, IconPlugX } from "@tabler/icons-react";
import type { RouterOutputs } from "@homarr/api";
import { api } from "@homarr/api/server";
@@ -40,6 +40,7 @@ import { CountBadge, IntegrationAvatar } from "@homarr/ui";
import { ManageContainer } from "~/components/manage/manage-container";
import { DynamicBreadcrumb } from "~/components/navigation/dynamic-breadcrumb";
+import { NoResults } from "~/components/no-results";
import { ActiveTabAccordion } from "../../../../components/active-tab-accordion";
import { DeleteIntegrationActionButton } from "./_integration-buttons";
import { IntegrationCreateDropdownContent } from "./new/_integration-new-dropdown";
@@ -120,7 +121,7 @@ const IntegrationList = async ({ integrations, activeTab }: IntegrationListProps
const hasFullAccess = session?.user.permissions.includes("integration-full-all") ?? false;
if (integrations.length === 0) {
- return
{t("page.list.empty")}
;
+ return ;
}
const grouppedIntegrations = integrations.reduce(
diff --git a/apps/nextjs/src/app/[locale]/manage/search-engines/page.tsx b/apps/nextjs/src/app/[locale]/manage/search-engines/page.tsx
index 8f66abbf1..5d56fe17c 100644
--- a/apps/nextjs/src/app/[locale]/manage/search-engines/page.tsx
+++ b/apps/nextjs/src/app/[locale]/manage/search-engines/page.tsx
@@ -13,6 +13,7 @@ import { z } from "@homarr/validation";
import { ManageContainer } from "~/components/manage/manage-container";
import { MobileAffixButton } from "~/components/manage/mobile-affix-button";
import { DynamicBreadcrumb } from "~/components/navigation/dynamic-breadcrumb";
+import { NoResults } from "~/components/no-results";
import { SearchEngineDeleteButton } from "./_search-engine-delete-button";
const searchParamsSchema = z.object({
@@ -142,16 +143,14 @@ const SearchEngineNoResults = async () => {
const session = await auth();
return (
-
-
-
-
- {t("search.engine.page.list.noResults.title")}
-
- {session?.user.permissions.includes("search-engine-create") && (
- {t("search.engine.page.list.noResults.action")}
- )}
-
-
+
);
};
diff --git a/apps/nextjs/src/components/no-results.tsx b/apps/nextjs/src/components/no-results.tsx
new file mode 100644
index 000000000..c25724297
--- /dev/null
+++ b/apps/nextjs/src/components/no-results.tsx
@@ -0,0 +1,26 @@
+import { Anchor, Card, Stack, Text } from "@mantine/core";
+import type { TablerIcon } from "@tabler/icons-react";
+
+interface NoResultsProps {
+ icon: TablerIcon;
+ title: string;
+ action?: {
+ label: string;
+ href: string;
+ hidden?: boolean;
+ };
+}
+
+export const NoResults = ({ icon: Icon, title, action }: NoResultsProps) => {
+ return (
+
+
+
+
+ {title}
+
+ {!action?.hidden && {action?.label}}
+
+
+ );
+};
diff --git a/packages/translation/src/lang/en.json b/packages/translation/src/lang/en.json
index 7b8655ed1..cac220e9f 100644
--- a/packages/translation/src/lang/en.json
+++ b/packages/translation/src/lang/en.json
@@ -388,7 +388,7 @@
"list": {
"title": "Apps",
"noResults": {
- "title": "There aren't any apps",
+ "title": "There are no apps yet",
"action": "Create your first app"
}
},
@@ -456,7 +456,9 @@
"list": {
"title": "Integrations",
"search": "Search integrations",
- "empty": "No integrations found"
+ "noResults": {
+ "title": "There are no integrations yet"
+ }
},
"create": {
"title": "New {name} integration",
@@ -2676,7 +2678,7 @@
"list": {
"title": "Search engines",
"noResults": {
- "title": "There aren't any search engines",
+ "title": "There are no search engines yet",
"action": "Create your first search engine"
},
"interactive": "Interactive, uses an integration"