chore: clean up unused imports and parameters across components

This commit is contained in:
Johnny 2025-12-27 10:18:38 +08:00
parent 0ad75b8f08
commit d711d724bb
15 changed files with 58 additions and 94 deletions

View File

@ -4,7 +4,7 @@ import { useCallback } from "react";
import toast from "react-hot-toast";
import { useLocation } from "react-router-dom";
import { useInstance } from "@/contexts/InstanceContext";
import { memoKeys, useDeleteMemo, useUpdateMemo } from "@/hooks/useMemoQueries";
import { useDeleteMemo, useUpdateMemo } from "@/hooks/useMemoQueries";
import useNavigateTo from "@/hooks/useNavigateTo";
import { userKeys } from "@/hooks/useUserQueries";
import { State } from "@/types/proto/api/v1/common_pb";

View File

@ -3,7 +3,7 @@ import { timestampDate } from "@bufbuild/protobuf/wkt";
import { isEqual } from "lodash-es";
import { CheckCircleIcon, Code2Icon, HashIcon, LinkIcon } from "lucide-react";
import { cn } from "@/lib/utils";
import { Memo, Memo_Property, Memo_PropertySchema, MemoRelation_Type } from "@/types/proto/api/v1/memo_service_pb";
import { Memo, Memo_PropertySchema, MemoRelation_Type } from "@/types/proto/api/v1/memo_service_pb";
import { useTranslate } from "@/utils/i18n";
import MemoRelationForceGraph from "../MemoRelationForceGraph";

View File

@ -25,7 +25,7 @@ export const LocationDialog = ({
open,
onOpenChange,
state,
locationInitialized,
locationInitialized: _locationInitialized,
onPositionChange,
onUpdateCoordinate,
onPlaceholderChange,

View File

@ -7,7 +7,7 @@ interface UseKeyboardOptions {
onToggleFocusMode?: () => void;
}
export const useKeyboard = (editorRef: React.RefObject<EditorRefActions | null>, options: UseKeyboardOptions) => {
export const useKeyboard = (_editorRef: React.RefObject<EditorRefActions | null>, options: UseKeyboardOptions) => {
useEffect(() => {
const handleKeyDown = (event: KeyboardEvent) => {
// Cmd/Ctrl + Enter to save

View File

@ -5,14 +5,7 @@ import { memoServiceClient } from "@/connect";
import { DEFAULT_LIST_MEMOS_PAGE_SIZE } from "@/helpers/consts";
import { extractUserIdFromName } from "@/helpers/resource-names";
import useCurrentUser from "@/hooks/useCurrentUser";
import {
Memo,
MemoRelation,
MemoRelation_Memo,
MemoRelation_MemoSchema,
MemoRelation_Type,
MemoRelationSchema,
} from "@/types/proto/api/v1/memo_service_pb";
import { Memo, MemoRelation, MemoRelation_MemoSchema, MemoRelation_Type, MemoRelationSchema } from "@/types/proto/api/v1/memo_service_pb";
interface UseLinkMemoParams {
isOpen: boolean;

View File

@ -1,6 +1,6 @@
import type { LocalFile } from "@/components/memo-metadata";
import type { Attachment } from "@/types/proto/api/v1/attachment_service_pb";
import type { Location, MemoRelation } from "@/types/proto/api/v1/memo_service_pb";
import type { MemoRelation } from "@/types/proto/api/v1/memo_service_pb";
import type { EditorAction, EditorState, LoadingKey } from "./types";
export const editorActions = {

View File

@ -2,7 +2,7 @@ import { create } from "@bufbuild/protobuf";
import { FieldMaskSchema } from "@bufbuild/protobuf/wkt";
import { sortBy } from "lodash-es";
import { MoreVerticalIcon, PlusIcon } from "lucide-react";
import React, { useState } from "react";
import { useState } from "react";
import toast from "react-hot-toast";
import ConfirmDialog from "@/components/ConfirmDialog";
import { Button } from "@/components/ui/button";

View File

@ -1,4 +1,3 @@
import { create } from "@bufbuild/protobuf";
import { isEqual } from "lodash-es";
import { XIcon } from "lucide-react";
import { useState } from "react";
@ -12,7 +11,6 @@ import { useInstance } from "@/contexts/InstanceContext";
import { convertFileToBase64 } from "@/helpers/utils";
import useCurrentUser from "@/hooks/useCurrentUser";
import { useUpdateUser } from "@/hooks/useUserQueries";
import { User as UserPb, UserSchema } from "@/types/proto/api/v1/user_service_pb";
import { useTranslate } from "@/utils/i18n";
import UserAvatar from "./UserAvatar";

View File

@ -89,8 +89,8 @@ const UserMenu = (props: Props) => {
try {
// Then clear user-specific localStorage items
// Preserve app-wide settings like theme
const keysToPreserve = ["memos-theme", "tag-view-as-tree", "tag-tree-auto-expand", "viewStore"];
// Preserve app-wide settings (theme, locale, view preferences, tag view settings)
const keysToPreserve = ["memos-theme", "memos-locale", "memos-view-setting", "tag-view-as-tree", "tag-tree-auto-expand"];
const keysToRemove: string[] = [];
for (let i = 0; i < localStorage.length; i++) {
@ -105,8 +105,8 @@ const UserMenu = (props: Props) => {
// Ignore errors from localStorage operations
}
// Always redirect to auth page
window.location.href = Routes.AUTH;
// Always redirect to auth page (use replace to prevent back navigation)
window.location.replace(Routes.AUTH);
};
return (

View File

@ -2,8 +2,6 @@ import { timestampDate } from "@bufbuild/protobuf/wkt";
import { Code, ConnectError, createClient, type Interceptor } from "@connectrpc/connect";
import { createConnectTransport } from "@connectrpc/connect-web";
import { getAccessToken, setAccessToken } from "./auth-state";
import { getInstanceConfig } from "./instance-config";
import { ROUTES } from "./router/routes";
import { ActivityService } from "./types/proto/api/v1/activity_service_pb";
import { AttachmentService } from "./types/proto/api/v1/attachment_service_pb";
import { AuthService } from "./types/proto/api/v1/auth_service_pb";
@ -12,6 +10,7 @@ import { InstanceService } from "./types/proto/api/v1/instance_service_pb";
import { MemoService } from "./types/proto/api/v1/memo_service_pb";
import { ShortcutService } from "./types/proto/api/v1/shortcut_service_pb";
import { UserService } from "./types/proto/api/v1/user_service_pb";
import { redirectOnAuthFailure } from "./utils/auth-redirect";
// ============================================================================
// Constants
@ -20,19 +19,6 @@ import { UserService } from "./types/proto/api/v1/user_service_pb";
const RETRY_HEADER = "X-Retry";
const RETRY_HEADER_VALUE = "true";
const ROUTE_CONFIG = {
// Routes accessible without authentication (uses prefix matching)
public: [
ROUTES.AUTH, // Authentication pages
ROUTES.EXPLORE, // Explore page
"/u/", // User profile pages (dynamic)
"/memos/", // Individual memo detail pages (dynamic)
],
// Routes that require authentication (uses exact matching)
private: [ROUTES.ROOT, ROUTES.ATTACHMENTS, ROUTES.INBOX, ROUTES.ARCHIVED, ROUTES.SETTING],
} as const;
// ============================================================================
// Token Refresh State Management
// ============================================================================
@ -60,42 +46,6 @@ const createTokenRefreshManager = () => {
const tokenRefreshManager = createTokenRefreshManager();
// ============================================================================
// Route Access Control
// ============================================================================
function isPublicRoute(path: string): boolean {
return ROUTE_CONFIG.public.some((route) => path.startsWith(route));
}
function isPrivateRoute(path: string): boolean {
return (ROUTE_CONFIG.private as readonly string[]).includes(path);
}
function getAuthFailureRedirect(currentPath: string): string | null {
if (isPublicRoute(currentPath)) {
return null;
}
if (getInstanceConfig().memoRelatedSetting.disallowPublicVisibility) {
return ROUTES.AUTH;
}
if (isPrivateRoute(currentPath)) {
return ROUTES.EXPLORE;
}
return null;
}
function performRedirect(redirectUrl: string | null): void {
if (redirectUrl) {
// Use replace() instead of href to prevent back button from showing cached sensitive data
// This removes the current page from browser history after authentication failure
window.location.replace(redirectUrl);
}
}
// ============================================================================
// Token Refresh
// ============================================================================
@ -165,8 +115,7 @@ const authInterceptor: Interceptor = (next) => async (req) => {
req.header.set(RETRY_HEADER, RETRY_HEADER_VALUE);
return await next(req);
} catch (refreshError) {
const redirectUrl = getAuthFailureRedirect(window.location.pathname);
performRedirect(redirectUrl);
redirectOnAuthFailure();
throw refreshError;
}
}

View File

@ -32,4 +32,3 @@ const useMediaQuery = (breakpoint: Breakpoint): boolean => {
};
export default useMediaQuery;

View File

@ -1,4 +1,4 @@
import { Suspense, useEffect, useMemo, useState } from "react";
import { Suspense, useEffect, useMemo } from "react";
import { Outlet, useLocation, useSearchParams } from "react-router-dom";
import usePrevious from "react-use/lib/usePrevious";
import Navigation from "@/components/Navigation";
@ -8,7 +8,7 @@ import useCurrentUser from "@/hooks/useCurrentUser";
import useMediaQuery from "@/hooks/useMediaQuery";
import { cn } from "@/lib/utils";
import Loading from "@/pages/Loading";
import { Routes } from "@/router";
import { redirectOnAuthFailure } from "@/utils/auth-redirect";
const RootLayout = () => {
const location = useLocation();
@ -17,25 +17,14 @@ const RootLayout = () => {
const currentUser = useCurrentUser();
const { memoRelatedSetting } = useInstance();
const { removeFilter } = useMemoFilterContext();
const [initialized, setInitialized] = useState(false);
const pathname = useMemo(() => location.pathname, [location.pathname]);
const prevPathname = usePrevious(pathname);
useEffect(() => {
if (!currentUser) {
// If disallowPublicVisibility is enabled, redirect to login
if (memoRelatedSetting.disallowPublicVisibility) {
window.location.replace(Routes.AUTH);
return;
} else if (
([Routes.ROOT, Routes.ATTACHMENTS, Routes.INBOX, Routes.ARCHIVED, Routes.SETTING] as string[]).includes(location.pathname)
) {
window.location.replace(Routes.EXPLORE);
return;
}
if (!currentUser && memoRelatedSetting.disallowPublicVisibility) {
redirectOnAuthFailure();
}
setInitialized(true);
}, [currentUser, memoRelatedSetting.disallowPublicVisibility, location.pathname]);
}, [currentUser, memoRelatedSetting.disallowPublicVisibility]);
useEffect(() => {
// When the route changes and there is no filter in the search params, remove all filters
@ -44,9 +33,7 @@ const RootLayout = () => {
}
}, [prevPathname, pathname, searchParams, removeFilter]);
return !initialized ? (
<Loading />
) : (
return (
<div className="w-full min-h-full flex flex-row justify-center items-start sm:pl-16">
{sm && (
<div

View File

@ -57,7 +57,7 @@ const MemoDetail = () => {
setShowCommentEditor(true);
};
const handleCommentCreated = async (memoCommentName: string) => {
const handleCommentCreated = async (_memoCommentName: string) => {
// React Query will auto-refetch due to invalidation in the mutation
setShowCommentEditor(false);
};

View File

@ -0,0 +1,36 @@
import { getInstanceConfig } from "@/instance-config";
import { ROUTES } from "@/router/routes";
const PUBLIC_ROUTES = [
ROUTES.AUTH, // Authentication pages
ROUTES.EXPLORE, // Explore page
"/u/", // User profile pages (dynamic)
"/memos/", // Individual memo detail pages (dynamic)
] as const;
const PRIVATE_ROUTES = [ROUTES.ROOT, ROUTES.ATTACHMENTS, ROUTES.INBOX, ROUTES.ARCHIVED, ROUTES.SETTING] as const;
function isPublicRoute(path: string): boolean {
return PUBLIC_ROUTES.some((route) => path.startsWith(route));
}
function isPrivateRoute(path: string): boolean {
return PRIVATE_ROUTES.includes(path as any);
}
export function redirectOnAuthFailure(): void {
const currentPath = window.location.pathname;
// Don't redirect if it's a public route
if (isPublicRoute(currentPath)) {
return;
}
const disallowPublicVisibility = getInstanceConfig().memoRelatedSetting.disallowPublicVisibility;
const target = disallowPublicVisibility ? ROUTES.AUTH : ROUTES.EXPLORE;
// Only redirect if it's a private route or disallowPublicVisibility is enabled
if (disallowPublicVisibility || isPrivateRoute(currentPath)) {
window.location.replace(target);
}
}

View File

@ -8,6 +8,8 @@
"esModuleInterop": false,
"allowSyntheticDefaultImports": true,
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"forceConsistentCasingInFileNames": true,
"module": "ESNext",
"moduleResolution": "Node",