mirror of
https://github.com/Portabase/portabase.git
synced 2026-07-14 11:16:13 +02:00
Ready for 1.1.2-rc.3
This commit is contained in:
@@ -0,0 +1,95 @@
|
||||
"use client"
|
||||
import {
|
||||
Breadcrumb,
|
||||
BreadcrumbItem, BreadcrumbLink,
|
||||
BreadcrumbList,
|
||||
BreadcrumbPage,
|
||||
BreadcrumbSeparator,
|
||||
} from "@/components/ui/breadcrumb";
|
||||
import {usePathname} from "next/navigation";
|
||||
import Link from "next/link";
|
||||
import {useIsMobile} from "@/hooks/use-mobile";
|
||||
import {capitalizeFirstLetter, isUUID} from "@/utils/text";
|
||||
|
||||
|
||||
export function useBreadCrumbs() {
|
||||
const pathname = usePathname();
|
||||
|
||||
const route_history = pathname
|
||||
.split("/")
|
||||
.filter((x: any) => x && x.length > 0);
|
||||
|
||||
const breadcrumb_routes = route_history.reduce(
|
||||
(acc: { name: string; path: string }[], route) => {
|
||||
const prev_path = acc[acc.length - 1]?.path ?? "";
|
||||
acc.push({name: route, path: `${prev_path}/${route}`});
|
||||
return acc;
|
||||
},
|
||||
[],
|
||||
);
|
||||
return {breadcrumb_routes};
|
||||
}
|
||||
|
||||
|
||||
interface BreadCrumbsProps {
|
||||
}
|
||||
|
||||
|
||||
export function BreadCrumbsWrapper() {
|
||||
const isMobile = useIsMobile()
|
||||
return (
|
||||
<>
|
||||
{!isMobile ? <BreadCrumbs/> : null}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
const FORBIDDEN_LINKS = ["organization", "dashboard", "database"];
|
||||
|
||||
|
||||
export function BreadCrumbs({}: BreadCrumbsProps) {
|
||||
const {breadcrumb_routes} = useBreadCrumbs();
|
||||
if (breadcrumb_routes.length < 2) return null;
|
||||
return (
|
||||
<div className="flex w-full flex-wrap px-3 md:justify-end">
|
||||
<Breadcrumb>
|
||||
<BreadcrumbList>
|
||||
{breadcrumb_routes.map((crumb: any) => {
|
||||
const label = isUUID(crumb.name) ? "details" : crumb.name;
|
||||
|
||||
const isLast = breadcrumb_routes.length - 1 === breadcrumb_routes.indexOf(crumb);
|
||||
const isForbidden = FORBIDDEN_LINKS.includes(crumb.name.toLowerCase());
|
||||
|
||||
return (
|
||||
<div className="flex items-center gap-2" key={crumb.path}>
|
||||
<BreadcrumbItem key={crumb.path}>
|
||||
{isLast ? (
|
||||
<BreadcrumbPage>{capitalizeFirstLetter(label)}</BreadcrumbPage>
|
||||
) : (
|
||||
<> {isForbidden ?
|
||||
<BreadcrumbLink asChild>
|
||||
<Link
|
||||
href={crumb.path}
|
||||
onClick={(e) => e.preventDefault()}
|
||||
className="cursor-not-allowed "
|
||||
>
|
||||
{capitalizeFirstLetter(label)}
|
||||
</Link>
|
||||
</BreadcrumbLink>
|
||||
:
|
||||
<BreadcrumbLink asChild>
|
||||
<Link href={crumb.path}>{capitalizeFirstLetter(label)}</Link>
|
||||
</BreadcrumbLink>
|
||||
}
|
||||
</>
|
||||
)}
|
||||
</BreadcrumbItem>
|
||||
{!isLast && <BreadcrumbSeparator className="hidden md:block"/>}
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</BreadcrumbList>
|
||||
</Breadcrumb>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -101,12 +101,10 @@ export function backupColumns(isAlreadyRestore: boolean, settings: Setting, data
|
||||
|
||||
const mutationDeleteBackup = useMutation({
|
||||
mutationFn: async () => {
|
||||
|
||||
|
||||
const deletion = await deleteBackupAction({
|
||||
backupId: rowData.id,
|
||||
databaseId: rowData.databaseId,
|
||||
file: rowData.file!,
|
||||
file: rowData.file ?? "",
|
||||
projectSlug: database.project?.slug!
|
||||
});
|
||||
// @ts-ignore
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
import { notFound } from "next/navigation";
|
||||
import {notFound} from "next/navigation";
|
||||
|
||||
import { SidebarTrigger } from "@/components/ui/sidebar";
|
||||
import { ModeToggle } from "@/features/theme/ModeToggle";
|
||||
import { currentUser } from "@/lib/auth/current-user";
|
||||
import {SidebarTrigger} from "@/components/ui/sidebar";
|
||||
import {ModeToggle} from "@/features/theme/ModeToggle";
|
||||
import {currentUser} from "@/lib/auth/current-user";
|
||||
import {LoggedInButton} from "@/components/wrappers/dashboard/common/logged-in/logged-in-button";
|
||||
import {BreadCrumbsWrapper} from "@/components/wrappers/common/bread-crumbs/bread-crumbs";
|
||||
|
||||
export const Header = async () => {
|
||||
const user = await currentUser();
|
||||
@@ -12,10 +13,14 @@ export const Header = async () => {
|
||||
}
|
||||
return (
|
||||
<header className="flex h-16 shrink-0 items-center justify-between border-b px-4">
|
||||
<SidebarTrigger className="-ml-1" />
|
||||
<div className="flex items-center justify-between">
|
||||
<SidebarTrigger className="-ml-1"/>
|
||||
<BreadCrumbsWrapper/>
|
||||
</div>
|
||||
|
||||
<div className="flex items-center gap-2">
|
||||
<ModeToggle />
|
||||
<LoggedInButton />
|
||||
<ModeToggle/>
|
||||
<LoggedInButton/>
|
||||
</div>
|
||||
</header>
|
||||
);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { twx } from "@/lib/twx";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
export const Page = twx.div((props) => [cn(`flex flex-col h-full px-10 py-6`, props.className)]);
|
||||
export const Page = twx.div((props) => [cn(`flex flex-col h-full px-5 md:px-10 py-6`, props.className)]);
|
||||
|
||||
export const PageHeader = twx.div((props) => [cn(`flex justify-between`, props.className)]);
|
||||
|
||||
|
||||
@@ -8,3 +8,10 @@ export function truncateWords(text: string, wordLimit: number = 10): string {
|
||||
export function capitalizeFirstLetter(text: string): string {
|
||||
return text ? text.charAt(0).toUpperCase() + text.slice(1) : "";
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
export function isUUID(str: string) {
|
||||
return /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(str);
|
||||
}
|
||||
Reference in New Issue
Block a user