aboutsummaryrefslogtreecommitdiffstats
path: root/apps/web/components/shared
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--apps/web/components/shared/sidebar/Sidebar.tsx5
-rw-r--r--apps/web/components/shared/sidebar/SidebarItem.tsx15
-rw-r--r--apps/web/components/shared/sidebar/SidebarLayout.tsx10
-rw-r--r--apps/web/components/shared/sidebar/SidebarVersion.tsx56
4 files changed, 66 insertions, 20 deletions
diff --git a/apps/web/components/shared/sidebar/Sidebar.tsx b/apps/web/components/shared/sidebar/Sidebar.tsx
index bf5a626b..3f4780e7 100644
--- a/apps/web/components/shared/sidebar/Sidebar.tsx
+++ b/apps/web/components/shared/sidebar/Sidebar.tsx
@@ -32,7 +32,10 @@ export default async function Sidebar({
</ul>
</div>
{extraSections}
- <SidebarVersion serverVersion={serverConfig.serverVersion} />
+ <SidebarVersion
+ serverVersion={serverConfig.serverVersion}
+ changeLogVersion={serverConfig.changelogVersion}
+ />
</aside>
);
}
diff --git a/apps/web/components/shared/sidebar/SidebarItem.tsx b/apps/web/components/shared/sidebar/SidebarItem.tsx
index e602a435..eb61d48b 100644
--- a/apps/web/components/shared/sidebar/SidebarItem.tsx
+++ b/apps/web/components/shared/sidebar/SidebarItem.tsx
@@ -14,6 +14,11 @@ export default function SidebarItem({
style,
collapseButton,
right = null,
+ dropHighlight = false,
+ onDrop,
+ onDragOver,
+ onDragEnter,
+ onDragLeave,
}: {
name: string;
logo: React.ReactNode;
@@ -23,6 +28,11 @@ export default function SidebarItem({
linkClassName?: string;
right?: React.ReactNode;
collapseButton?: React.ReactNode;
+ dropHighlight?: boolean;
+ onDrop?: React.DragEventHandler;
+ onDragOver?: React.DragEventHandler;
+ onDragEnter?: React.DragEventHandler;
+ onDragLeave?: React.DragEventHandler;
}) {
const currentPath = usePathname();
return (
@@ -32,9 +42,14 @@ export default function SidebarItem({
path == currentPath
? "bg-accent/50 text-foreground"
: "text-muted-foreground",
+ dropHighlight && "bg-accent ring-2 ring-primary",
className,
)}
style={style}
+ onDrop={onDrop}
+ onDragOver={onDragOver}
+ onDragEnter={onDragEnter}
+ onDragLeave={onDragLeave}
>
<div className="flex-1">
{collapseButton}
diff --git a/apps/web/components/shared/sidebar/SidebarLayout.tsx b/apps/web/components/shared/sidebar/SidebarLayout.tsx
index 8ea8655e..e1b35634 100644
--- a/apps/web/components/shared/sidebar/SidebarLayout.tsx
+++ b/apps/web/components/shared/sidebar/SidebarLayout.tsx
@@ -1,7 +1,11 @@
+import { Suspense } from "react";
+import ErrorFallback from "@/components/dashboard/ErrorFallback";
import Header from "@/components/dashboard/header/Header";
import DemoModeBanner from "@/components/DemoModeBanner";
import { Separator } from "@/components/ui/separator";
+import LoadingSpinner from "@/components/ui/spinner";
import ValidAccountCheck from "@/components/utils/ValidAccountCheck";
+import { ErrorBoundary } from "react-error-boundary";
import serverConfig from "@karakeep/shared/config";
@@ -29,7 +33,11 @@ export default function SidebarLayout({
<Separator />
</div>
{modal}
- <div className="min-h-30 container p-4">{children}</div>
+ <div className="min-h-30 container p-4">
+ <ErrorBoundary fallback={<ErrorFallback />}>
+ <Suspense fallback={<LoadingSpinner />}>{children}</Suspense>
+ </ErrorBoundary>
+ </div>
</main>
</div>
</div>
diff --git a/apps/web/components/shared/sidebar/SidebarVersion.tsx b/apps/web/components/shared/sidebar/SidebarVersion.tsx
index fc2ec5a3..2d6d3380 100644
--- a/apps/web/components/shared/sidebar/SidebarVersion.tsx
+++ b/apps/web/components/shared/sidebar/SidebarVersion.tsx
@@ -46,36 +46,50 @@ function isStableRelease(version?: string) {
}
interface SidebarVersionProps {
+ // The actual version of the server
serverVersion?: string;
+ // The version that should be displayed in the changelog
+ changeLogVersion?: string;
}
-export default function SidebarVersion({ serverVersion }: SidebarVersionProps) {
+export default function SidebarVersion({
+ serverVersion,
+ changeLogVersion,
+}: SidebarVersionProps) {
const { disableNewReleaseCheck } = useClientConfig();
const { t } = useTranslation();
- const stableRelease = isStableRelease(serverVersion);
+ const effectiveChangelogVersion = changeLogVersion ?? serverVersion;
+ const stableRelease = isStableRelease(effectiveChangelogVersion);
const displayVersion = serverVersion ?? "unknown";
+ const changelogDisplayVersion = effectiveChangelogVersion ?? displayVersion;
const versionLabel = `Karakeep v${displayVersion}`;
const releasePageUrl = useMemo(() => {
- if (!serverVersion || !isStableRelease(serverVersion)) {
+ if (
+ !effectiveChangelogVersion ||
+ !isStableRelease(effectiveChangelogVersion)
+ ) {
return GITHUB_REPO_URL;
}
- return `${GITHUB_RELEASE_URL}v${serverVersion}`;
- }, [serverVersion]);
+ return `${GITHUB_RELEASE_URL}v${effectiveChangelogVersion}`;
+ }, [effectiveChangelogVersion]);
const [open, setOpen] = useState(false);
const [shouldNotify, setShouldNotify] = useState(false);
const releaseNotesQuery = useQuery<string>({
- queryKey: ["sidebar-release-notes", serverVersion],
+ queryKey: ["sidebar-release-notes", effectiveChangelogVersion],
queryFn: async ({ signal }) => {
- if (!serverVersion) {
+ if (!effectiveChangelogVersion) {
return "";
}
- const response = await fetch(`${RELEASE_API_URL}v${serverVersion}`, {
- signal,
- });
+ const response = await fetch(
+ `${RELEASE_API_URL}v${effectiveChangelogVersion}`,
+ {
+ signal,
+ },
+ );
if (!response.ok) {
throw new Error("Failed to load release notes");
@@ -89,7 +103,7 @@ export default function SidebarVersion({ serverVersion }: SidebarVersionProps) {
open &&
stableRelease &&
!disableNewReleaseCheck &&
- Boolean(serverVersion),
+ Boolean(effectiveChangelogVersion),
staleTime: RELEASE_NOTES_STALE_TIME,
retry: 1,
refetchOnWindowFocus: false,
@@ -123,30 +137,34 @@ export default function SidebarVersion({ serverVersion }: SidebarVersionProps) {
}, [releaseNotesQuery.error, t]);
useEffect(() => {
- if (!stableRelease || !serverVersion || disableNewReleaseCheck) {
+ if (
+ !stableRelease ||
+ !effectiveChangelogVersion ||
+ disableNewReleaseCheck
+ ) {
setShouldNotify(false);
return;
}
try {
const seenVersion = window.localStorage.getItem(LOCAL_STORAGE_KEY);
- setShouldNotify(seenVersion !== serverVersion);
+ setShouldNotify(seenVersion !== effectiveChangelogVersion);
} catch (error) {
console.warn("Failed to read localStorage:", error);
setShouldNotify(true);
}
- }, [serverVersion, stableRelease, disableNewReleaseCheck]);
+ }, [effectiveChangelogVersion, stableRelease, disableNewReleaseCheck]);
const markReleaseAsSeen = useCallback(() => {
- if (!serverVersion) return;
+ if (!effectiveChangelogVersion) return;
try {
- window.localStorage.setItem(LOCAL_STORAGE_KEY, serverVersion);
+ window.localStorage.setItem(LOCAL_STORAGE_KEY, effectiveChangelogVersion);
} catch (error) {
console.warn("Failed to write to localStorage:", error);
// Ignore failures, we still clear the notification for the session
}
setShouldNotify(false);
- }, [serverVersion]);
+ }, [effectiveChangelogVersion]);
const handleOpenChange = useCallback(
(nextOpen: boolean) => {
@@ -202,7 +220,9 @@ export default function SidebarVersion({ serverVersion }: SidebarVersionProps) {
<DialogContent className="max-w-3xl">
<DialogHeader>
<DialogTitle>
- {t("version.whats_new_title", { version: displayVersion })}
+ {t("version.whats_new_title", {
+ version: changelogDisplayVersion,
+ })}
</DialogTitle>
<DialogDescription>
{t("version.release_notes_description")}