Skip to content

Commit

Permalink
feat: add dynamic breadcrumb (#706)
Browse files Browse the repository at this point in the history
* feat: add dynamic breadcrumb

* feat: pr feedback
  • Loading branch information
manuel-rw authored Jun 29, 2024
1 parent be100b6 commit 4e1bbf2
Show file tree
Hide file tree
Showing 21 changed files with 258 additions and 58 deletions.
2 changes: 2 additions & 0 deletions apps/nextjs/src/app/[locale]/manage/about/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import { setStaticParamsLocale } from "next-international/server";
import { getScopedI18n, getStaticParams } from "@homarr/translation/server";

import { homarrLogoPath } from "~/components/layout/logo/homarr-logo";
import { DynamicBreadcrumb } from "~/components/navigation/dynamic-breadcrumb";
import { createMetaTitle } from "~/metadata";
import { getPackageAttributesAsync } from "~/versions/package-reader";
import contributorsData from "../../../../../../../static-data/contributors.json";
Expand All @@ -48,6 +49,7 @@ export default async function AboutPage({ params: { locale } }: PageProps) {
const attributes = await getPackageAttributesAsync();
return (
<div>
<DynamicBreadcrumb />
<Center w="100%">
<Group py="lg">
<Image src={homarrLogoPath} width={100} height={100} alt="" />
Expand Down
16 changes: 10 additions & 6 deletions apps/nextjs/src/app/[locale]/manage/apps/edit/[id]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { Container, Stack, Title } from "@mantine/core";
import { api } from "@homarr/api/server";
import { getI18n } from "@homarr/translation/server";

import { DynamicBreadcrumb } from "~/components/navigation/dynamic-breadcrumb";
import { AppEditForm } from "./_app-edit-form";

interface AppEditPageProps {
Expand All @@ -14,11 +15,14 @@ export default async function AppEditPage({ params }: AppEditPageProps) {
const t = await getI18n();

return (
<Container>
<Stack>
<Title>{t("app.page.edit.title")}</Title>
<AppEditForm app={app} />
</Stack>
</Container>
<>
<DynamicBreadcrumb dynamicMappings={new Map([[params.id, app.name]])} nonInteractable={["edit"]} />
<Container>
<Stack>
<Title>{t("app.page.edit.title")}</Title>
<AppEditForm app={app} />
</Stack>
</Container>
</>
);
}
16 changes: 10 additions & 6 deletions apps/nextjs/src/app/[locale]/manage/apps/new/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,21 @@ import { Container, Stack, Title } from "@mantine/core";

import { getI18n } from "@homarr/translation/server";

import { DynamicBreadcrumb } from "~/components/navigation/dynamic-breadcrumb";
import { AppNewForm } from "./_app-new-form";

export default async function AppNewPage() {
const t = await getI18n();

return (
<Container>
<Stack>
<Title>{t("app.page.create.title")}</Title>
<AppNewForm />
</Stack>
</Container>
<>
<DynamicBreadcrumb />
<Container>
<Stack>
<Title>{t("app.page.create.title")}</Title>
<AppNewForm />
</Stack>
</Container>
</>
);
}
2 changes: 2 additions & 0 deletions apps/nextjs/src/app/[locale]/manage/apps/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,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 { AppDeleteButton } from "./_app-delete-button";

export default async function AppsPage() {
Expand All @@ -16,6 +17,7 @@ export default async function AppsPage() {

return (
<ManageContainer>
<DynamicBreadcrumb />
<Stack>
<Group justify="space-between" align="center">
<Title>{t("page.list.title")}</Title>
Expand Down
2 changes: 2 additions & 0 deletions apps/nextjs/src/app/[locale]/manage/boards/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import { UserAvatar } from "@homarr/ui";

import { getBoardPermissionsAsync } from "~/components/board/permissions/server";
import { ManageContainer } from "~/components/manage/manage-container";
import { DynamicBreadcrumb } from "~/components/navigation/dynamic-breadcrumb";
import { BoardCardMenuDropdown } from "./_components/board-card-menu-dropdown";
import { CreateBoardButton } from "./_components/create-board-button";

Expand All @@ -34,6 +35,7 @@ export default async function ManageBoardsPage() {

return (
<ManageContainer>
<DynamicBreadcrumb />
<Stack>
<Group justify="space-between">
<Title mb="md">{t("title")}</Title>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { api } from "@homarr/api/server";
import { getIntegrationName } from "@homarr/definitions";
import { getScopedI18n } from "@homarr/translation/server";

import { DynamicBreadcrumb } from "~/components/navigation/dynamic-breadcrumb";
import { IntegrationAvatar } from "../../_integration-avatar";
import { EditIntegrationForm } from "./_integration-edit-form";

Expand All @@ -16,14 +17,17 @@ export default async function EditIntegrationPage({ params }: EditIntegrationPag
const integration = await api.integration.byId({ id: params.id });

return (
<Container>
<Stack>
<Group align="center">
<IntegrationAvatar kind={integration.kind} size="md" />
<Title>{t("title", { name: getIntegrationName(integration.kind) })}</Title>
</Group>
<EditIntegrationForm integration={integration} />
</Stack>
</Container>
<>
<DynamicBreadcrumb dynamicMappings={new Map([[params.id, integration.name]])} nonInteractable={["edit"]} />
<Container>
<Stack>
<Group align="center">
<IntegrationAvatar kind={integration.kind} size="md" />
<Title>{t("title", { name: getIntegrationName(integration.kind) })}</Title>
</Group>
<EditIntegrationForm integration={integration} />
</Stack>
</Container>
</>
);
}
22 changes: 13 additions & 9 deletions apps/nextjs/src/app/[locale]/manage/integrations/new/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { getScopedI18n } from "@homarr/translation/server";
import type { validation } from "@homarr/validation";
import { z } from "@homarr/validation";

import { DynamicBreadcrumb } from "~/components/navigation/dynamic-breadcrumb";
import { IntegrationAvatar } from "../_integration-avatar";
import { NewIntegrationForm } from "./_integration-new-form";

Expand All @@ -28,14 +29,17 @@ export default async function IntegrationsNewPage({ searchParams }: NewIntegrati
const currentKind = result.data;

return (
<Container>
<Stack>
<Group align="center">
<IntegrationAvatar kind={currentKind} size="md" />
<Title>{t("title", { name: getIntegrationName(currentKind) })}</Title>
</Group>
<NewIntegrationForm searchParams={searchParams} />
</Stack>
</Container>
<>
<DynamicBreadcrumb />
<Container>
<Stack>
<Group align="center">
<IntegrationAvatar kind={currentKind} size="md" />
<Title>{t("title", { name: getIntegrationName(currentKind) })}</Title>
</Group>
<NewIntegrationForm searchParams={searchParams} />
</Stack>
</Container>
</>
);
}
2 changes: 2 additions & 0 deletions apps/nextjs/src/app/[locale]/manage/integrations/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ import { getScopedI18n } from "@homarr/translation/server";
import { CountBadge } from "@homarr/ui";

import { ManageContainer } from "~/components/manage/manage-container";
import { DynamicBreadcrumb } from "~/components/navigation/dynamic-breadcrumb";
import { ActiveTabAccordion } from "../../../../components/active-tab-accordion";
import { IntegrationAvatar } from "./_integration-avatar";
import { DeleteIntegrationActionButton } from "./_integration-buttons";
Expand All @@ -54,6 +55,7 @@ export default async function IntegrationsPage({ searchParams }: IntegrationsPag

return (
<ManageContainer>
<DynamicBreadcrumb />
<Stack>
<Group justify="space-between" align="center">
<Title>{t("page.list.title")}</Title>
Expand Down
2 changes: 2 additions & 0 deletions apps/nextjs/src/app/[locale]/manage/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { IconArrowRight } from "@tabler/icons-react";
import { api } from "@homarr/api/server";
import { getScopedI18n } from "@homarr/translation/server";

import { DynamicBreadcrumb } from "~/components/navigation/dynamic-breadcrumb";
import { createMetaTitle } from "~/metadata";
import { HeroBanner } from "./_components/hero-banner";

Expand Down Expand Up @@ -67,6 +68,7 @@ export default async function ManagementPage() {
];
return (
<>
<DynamicBreadcrumb />
<HeroBanner />
<Space h="md" />
<SimpleGrid cols={{ xs: 1, sm: 2, md: 3 }}>
Expand Down
12 changes: 8 additions & 4 deletions apps/nextjs/src/app/[locale]/manage/settings/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { Stack, Title } from "@mantine/core";
import { api } from "@homarr/api/server";
import { getScopedI18n } from "@homarr/translation/server";

import { DynamicBreadcrumb } from "~/components/navigation/dynamic-breadcrumb";
import { AnalyticsSettings } from "./_components/analytics.settings";

export async function generateMetadata() {
Expand All @@ -18,9 +19,12 @@ export default async function SettingsPage() {
const serverSettings = await api.serverSettings.getAll();
const t = await getScopedI18n("management.page.settings");
return (
<Stack>
<Title order={1}>{t("title")}</Title>
<AnalyticsSettings initialData={serverSettings.analytics} />
</Stack>
<>
<DynamicBreadcrumb />
<Stack>
<Title order={1}>{t("title")}</Title>
<AnalyticsSettings initialData={serverSettings.analytics} />
</Stack>
</>
);
}
12 changes: 8 additions & 4 deletions apps/nextjs/src/app/[locale]/manage/tools/docker/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,20 @@ import { Stack, Title } from "@mantine/core";
import { api } from "@homarr/api/server";
import { getScopedI18n } from "@homarr/translation/server";

import { DynamicBreadcrumb } from "~/components/navigation/dynamic-breadcrumb";
import { DockerTable } from "./DockerTable";

export default async function DockerPage() {
const { containers, timestamp } = await api.docker.getContainers();
const tDocker = await getScopedI18n("docker");

return (
<Stack>
<Title order={1}>{tDocker("title")}</Title>
<DockerTable containers={containers} timestamp={timestamp} />
</Stack>
<>
<DynamicBreadcrumb />
<Stack>
<Title order={1}>{tDocker("title")}</Title>
<DockerTable containers={containers} timestamp={timestamp} />
</Stack>
</>
);
}
10 changes: 7 additions & 3 deletions apps/nextjs/src/app/[locale]/manage/tools/logs/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import "@xterm/xterm/css/xterm.css";

import dynamic from "next/dynamic";

import { DynamicBreadcrumb } from "~/components/navigation/dynamic-breadcrumb";
import { fullHeightWithoutHeaderAndFooter } from "~/constants";
import { createMetaTitle } from "~/metadata";

Expand All @@ -23,8 +24,11 @@ const ClientSideTerminalComponent = dynamic(() => import("./terminal"), {

export default function LogsManagementPage() {
return (
<Box style={{ borderRadius: 6 }} h={fullHeightWithoutHeaderAndFooter} p="md" bg="black">
<ClientSideTerminalComponent />
</Box>
<>
<DynamicBreadcrumb />
<Box style={{ borderRadius: 6 }} h={fullHeightWithoutHeaderAndFooter} p="md" bg="black">
<ClientSideTerminalComponent />
</Box>
</>
);
}
30 changes: 16 additions & 14 deletions apps/nextjs/src/app/[locale]/manage/users/[userId]/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import type { PropsWithChildren } from "react";
import Link from "next/link";
import { notFound } from "next/navigation";
import { Button, Grid, GridCol, Group, Stack, Text, Title } from "@mantine/core";
import { Grid, GridCol, Group, Stack, Text, Title } from "@mantine/core";
import { IconSettings, IconShieldLock } from "@tabler/icons-react";

import { api } from "@homarr/api/server";
Expand All @@ -10,6 +9,7 @@ import { getI18n, getScopedI18n } from "@homarr/translation/server";
import { UserAvatar } from "@homarr/ui";

import { ManageContainer } from "~/components/manage/manage-container";
import { DynamicBreadcrumb } from "~/components/navigation/dynamic-breadcrumb";
import { catchTrpcNotFound } from "~/errors/trpc-not-found";
import { NavigationLink } from "../groups/[id]/_navigation";
import { canAccessUserEditPage } from "./access";
Expand All @@ -30,21 +30,23 @@ export default async function Layout({ children, params }: PropsWithChildren<Lay

return (
<ManageContainer size="xl">
<DynamicBreadcrumb
dynamicMappings={
new Map([
[params.userId, user.name ?? ""],
["general", t("navigationStructure.manage.users.general")],
["security", t("navigationStructure.manage.users.security")],
])
}
/>
<Grid>
<GridCol span={12}>
<Group justify="space-between" align="center">
<Group>
<UserAvatar user={user} size="lg" />
<Stack gap={0}>
<Title order={3}>{user.name}</Title>
<Text c="gray.5">{t("user.name")}</Text>
</Stack>
</Group>
{session?.user.permissions.includes("admin") && (
<Button component={Link} href="/manage/users" color="gray" variant="light">
{tUser("back")}
</Button>
)}
<UserAvatar user={user} size="lg" />
<Stack gap={0}>
<Title order={3}>{user.name}</Title>
<Text c="gray.5">{t("user.name")}</Text>
</Stack>
</Group>
</GridCol>
<GridCol span={{ xs: 12, md: 4, lg: 3, xl: 2 }}>
Expand Down
8 changes: 7 additions & 1 deletion apps/nextjs/src/app/[locale]/manage/users/create/page.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { getScopedI18n } from "@homarr/translation/server";

import { DynamicBreadcrumb } from "~/components/navigation/dynamic-breadcrumb";
import { createMetaTitle } from "~/metadata";
import { UserCreateStepperComponent } from "./_components/create-user-stepper";

Expand All @@ -12,5 +13,10 @@ export async function generateMetadata() {
}

export default function CreateUserPage() {
return <UserCreateStepperComponent />;
return (
<>
<DynamicBreadcrumb />
<UserCreateStepperComponent />
</>
);
}
2 changes: 2 additions & 0 deletions apps/nextjs/src/app/[locale]/manage/users/groups/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { SearchInput, TablePagination, UserAvatarGroup } from "@homarr/ui";
import { z } from "@homarr/validation";

import { ManageContainer } from "~/components/manage/manage-container";
import { DynamicBreadcrumb } from "~/components/navigation/dynamic-breadcrumb";
import { AddGroup } from "./_add-group";

const searchParamsSchema = z.object({
Expand All @@ -31,6 +32,7 @@ export default async function GroupsListPage(props: GroupsListPageProps) {

return (
<ManageContainer size="xl">
<DynamicBreadcrumb />
<Stack>
<Title>{t("group.title")}</Title>
<Group justify="space-between">
Expand Down
8 changes: 7 additions & 1 deletion apps/nextjs/src/app/[locale]/manage/users/invites/page.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,14 @@
import { api } from "@homarr/api/server";

import { DynamicBreadcrumb } from "~/components/navigation/dynamic-breadcrumb";
import { InviteListComponent } from "./_components/invite-list";

export default async function InvitesOverviewPage() {
const initialInvites = await api.invite.getAll();
return <InviteListComponent initialInvites={initialInvites} />;
return (
<>
<DynamicBreadcrumb />
<InviteListComponent initialInvites={initialInvites} />
</>
);
}
Loading

0 comments on commit 4e1bbf2

Please sign in to comment.