aboutsummaryrefslogtreecommitdiffstats
path: root/apps/web/components
diff options
context:
space:
mode:
authorMohamed Bassem <me@mbassem.com>2024-12-21 21:35:35 +0000
committerMohamed Bassem <me@mbassem.com>2024-12-21 21:35:35 +0000
commit4bfb3b4250efa735aa265e924680a36a4b8bb1a7 (patch)
tree29b972fcc2ffb9542a6a5baf3359434dfb281104 /apps/web/components
parent22458873594fa1b157782afbbf1abca30259e7ab (diff)
downloadkarakeep-4bfb3b4250efa735aa265e924680a36a4b8bb1a7.tar.zst
feature: Add an admin notice about the usage of the legacy container images
Diffstat (limited to 'apps/web/components')
-rw-r--r--apps/web/components/dashboard/admin/AdminCard.tsx3
-rw-r--r--apps/web/components/dashboard/admin/AdminNotices.tsx71
-rw-r--r--apps/web/components/dashboard/header/ProfileOptions.tsx11
-rw-r--r--apps/web/components/ui/alert.tsx60
4 files changed, 142 insertions, 3 deletions
diff --git a/apps/web/components/dashboard/admin/AdminCard.tsx b/apps/web/components/dashboard/admin/AdminCard.tsx
new file mode 100644
index 00000000..3a52b5e5
--- /dev/null
+++ b/apps/web/components/dashboard/admin/AdminCard.tsx
@@ -0,0 +1,3 @@
+export function AdminCard({ children }: { children: React.ReactNode }) {
+ return <div className="rounded-md border bg-background p-4">{children}</div>;
+}
diff --git a/apps/web/components/dashboard/admin/AdminNotices.tsx b/apps/web/components/dashboard/admin/AdminNotices.tsx
new file mode 100644
index 00000000..4977736f
--- /dev/null
+++ b/apps/web/components/dashboard/admin/AdminNotices.tsx
@@ -0,0 +1,71 @@
+"use client";
+
+import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert";
+import { Badge } from "@/components/ui/badge";
+import { api } from "@/lib/trpc";
+import { AlertCircle } from "lucide-react";
+
+import { AdminCard } from "./AdminCard";
+
+interface AdminNotice {
+ level: "info" | "warning" | "error";
+ message: React.ReactNode;
+ title: string;
+}
+
+function useAdminNotices() {
+ const { data } = api.admin.getAdminNoticies.useQuery();
+ if (!data) {
+ return [];
+ }
+ const ret: AdminNotice[] = [];
+ if (data.legacyContainersNotice) {
+ ret.push({
+ level: "warning",
+ message: (
+ <p>
+ You&apos;re using the legacy docker container images. Those will stop
+ getting supported soon. Please follow{" "}
+ <a
+ href="https://docs.hoarder.app/next/Guides/legacy-container-upgrade"
+ className="underline"
+ >
+ this guide
+ </a>{" "}
+ to upgrade.
+ </p>
+ ),
+ title: "Legacy Container Images",
+ });
+ }
+ return ret;
+}
+
+export function AdminNotices() {
+ const notices = useAdminNotices();
+
+ if (notices.length === 0) {
+ return null;
+ }
+ return (
+ <AdminCard>
+ <div className="flex flex-col gap-2">
+ {notices.map((n, i) => (
+ <Alert key={i} variant="destructive">
+ <AlertCircle className="h-4 w-4" />
+ <AlertTitle>{n.title}</AlertTitle>
+ <AlertDescription>{n.message}</AlertDescription>
+ </Alert>
+ ))}
+ </div>
+ </AdminCard>
+ );
+}
+
+export function AdminNoticeBadge() {
+ const notices = useAdminNotices();
+ if (notices.length === 0) {
+ return null;
+ }
+ return <Badge variant="destructive">{notices.length}</Badge>;
+}
diff --git a/apps/web/components/dashboard/header/ProfileOptions.tsx b/apps/web/components/dashboard/header/ProfileOptions.tsx
index 3dbfcf04..fc18e9d2 100644
--- a/apps/web/components/dashboard/header/ProfileOptions.tsx
+++ b/apps/web/components/dashboard/header/ProfileOptions.tsx
@@ -16,6 +16,8 @@ import { LogOut, Moon, Paintbrush, Settings, Shield, Sun } from "lucide-react";
import { signOut, useSession } from "next-auth/react";
import { useTheme } from "next-themes";
+import { AdminNoticeBadge } from "../admin/AdminNotices";
+
function DarkModeToggle() {
const { t } = useTranslation();
const { theme } = useTheme();
@@ -72,9 +74,12 @@ export default function SidebarProfileOptions() {
</DropdownMenuItem>
{session.user.role == "admin" && (
<DropdownMenuItem asChild>
- <Link href="/dashboard/admin">
- <Shield className="mr-2 size-4" />
- {t("admin.admin_settings")}
+ <Link href="/dashboard/admin" className="flex justify-between">
+ <div className="items-cente flex gap-2">
+ <Shield className="size-4" />
+ {t("admin.admin_settings")}
+ </div>
+ <AdminNoticeBadge />
</Link>
</DropdownMenuItem>
)}
diff --git a/apps/web/components/ui/alert.tsx b/apps/web/components/ui/alert.tsx
new file mode 100644
index 00000000..706b711e
--- /dev/null
+++ b/apps/web/components/ui/alert.tsx
@@ -0,0 +1,60 @@
+import type { VariantProps } from "class-variance-authority";
+import * as React from "react";
+import { cn } from "@/lib/utils";
+import { cva } from "class-variance-authority";
+
+const alertVariants = cva(
+ "relative w-full rounded-lg border p-4 [&>svg+div]:translate-y-[-3px] [&>svg]:absolute [&>svg]:left-4 [&>svg]:top-4 [&>svg]:text-foreground [&>svg~*]:pl-7",
+ {
+ variants: {
+ variant: {
+ default: "bg-background text-foreground",
+ destructive:
+ "border-destructive/50 text-destructive dark:border-destructive [&>svg]:text-destructive",
+ },
+ },
+ defaultVariants: {
+ variant: "default",
+ },
+ },
+);
+
+const Alert = React.forwardRef<
+ HTMLDivElement,
+ React.HTMLAttributes<HTMLDivElement> & VariantProps<typeof alertVariants>
+>(({ className, variant, ...props }, ref) => (
+ <div
+ ref={ref}
+ role="alert"
+ className={cn(alertVariants({ variant }), className)}
+ {...props}
+ />
+));
+Alert.displayName = "Alert";
+
+const AlertTitle = React.forwardRef<
+ HTMLParagraphElement,
+ React.HTMLAttributes<HTMLHeadingElement>
+>(({ className, ...props }, ref) => (
+ // eslint-disable-next-line jsx-a11y/heading-has-content
+ <h5
+ ref={ref}
+ className={cn("mb-1 font-medium leading-none tracking-tight", className)}
+ {...props}
+ />
+));
+AlertTitle.displayName = "AlertTitle";
+
+const AlertDescription = React.forwardRef<
+ HTMLParagraphElement,
+ React.HTMLAttributes<HTMLParagraphElement>
+>(({ className, ...props }, ref) => (
+ <div
+ ref={ref}
+ className={cn("text-sm [&_p]:leading-relaxed", className)}
+ {...props}
+ />
+));
+AlertDescription.displayName = "AlertDescription";
+
+export { Alert, AlertTitle, AlertDescription };