Skip to content

Conversation

@appflowy
Copy link
Contributor

@appflowy appflowy commented Dec 2, 2025

Description


Checklist

General

  • I've included relevant documentation or comments for the changes introduced.
  • I've tested the changes in multiple environments (e.g., different browsers, operating systems).

Testing

  • I've added or updated tests to validate the changes introduced for AppFlowy Web.

Feature-Specific

  • For feature additions, I've added a preview (video, screenshot, or demo) in the "Feature Preview" section.
  • I've verified that this feature integrates seamlessly with existing functionality.

Summary by Sourcery

Standardize debug logging across the app to use the shared Log utility instead of direct console.debug calls.

Enhancements:

  • Route existing debug logging in calendar, editor, database, auth, WebSocket, awareness, and HTTP modules through the centralized Log helper.
  • Update local debug helpers and hooks to depend on Log.debug while preserving development-only logging behavior.

Chores:

  • Clean up scattered console.debug usage throughout the codebase for more consistent and controllable logging.

@sourcery-ai
Copy link

sourcery-ai bot commented Dec 2, 2025

Reviewer's Guide

Replaces direct console.debug usages with the central Log.debug helper across various components, hooks, and utilities, and wires in the Log import where needed to standardize debug logging behavior.

File-Level Changes

Change Details Files
Standardize debug logging by replacing console.debug with Log.debug and importing Log where required.
  • In UI components and hooks (calendar, database, editor, auth, templates, workspace redirect, header users, drag-and-drop, etc.), replace console.debug calls with Log.debug to route debug logs through the shared logging utility.
  • In Slate/Yjs sync utilities and database/yjs dispatch logic, swap console.debug to Log.debug for event translation, text operations, node movement, and cell/type option updates.
  • In HTTP, WebSocket, broadcast channel, and sync protocol services, update request/response, OAuth, upload, cache, websocket connection, sync initialization, and awareness debug logs to use Log.debug.
  • Introduce or update Log imports (e.g., from '@/utils/log') in files that previously used console.debug directly, ensuring type signatures and helper wrappers (like logDebug) now delegate to Log.debug.
  • Keep console.error/console.warn where appropriate for error-level logging while only redirecting debug-level logging to Log.debug.
src/components/database/fullcalendar/hooks/useCalendarEvents.ts
src/components/view-meta/TitleEditable.tsx
src/components/editor/components/panels/slash-panel/SlashPanel.tsx
src/application/slate-yjs/utils/applyToSlate.ts
src/components/editor/components/blocks/database/hooks/useDatabaseLoading.ts
src/application/slate-yjs/utils/applyTextToSlate.ts
src/application/services/js-services/http/http_api.ts
src/application/slate-yjs/utils/transformSelection.ts
src/components/app/hooks/useViewOperations.ts
src/components/app/layers/AppAuthLayer.tsx
src/components/database/fullcalendar/event/EventPopoverContent.tsx
src/components/ws/useSync.ts
src/application/awareness/dispatch.ts
src/application/services/js-services/sync-protocol.ts
src/components/database/fullcalendar/CalendarContent.tsx
src/components/database/fullcalendar/NoDateRow.tsx
src/application/slate-yjs/utils/applyToYjs.ts
src/application/user-metadata.ts
src/components/database/DatabaseViews.tsx
src/components/ws/useBroadcastChannel.ts
src/application/awareness/selector.ts
src/application/database-yjs/dispatch.ts
src/components/app/AppWorkspaceRedirect.tsx
src/components/database/components/board/card/useBottomEdgeIntersection.tsx
src/components/database/components/cell/date/DateTimeInput.tsx
src/components/database/components/grid/drag-and-drop/GridDragContext.tsx
src/components/database/components/settings/usePropertyDragContext.ts
src/components/database/fullcalendar/FullCalendar.tsx
src/components/database/fullcalendar/hooks/useScrollNavigation.ts
src/components/editor/components/blocks/database/hooks/useRetryFunction.ts
src/components/database/components/drag-and-drop/useDragContext.ts
src/application/db/index.ts
src/application/services/js-services/cache/index.ts
src/application/slate-yjs/utils/yjs.ts
src/components/app/header/Users.tsx
src/components/as-template/category/EditCategory.tsx
src/components/as-template/creator/AddCreator.tsx
src/components/database/Database.tsx
src/components/database/components/board/card/CardPrimitive.tsx
src/components/database/components/board/group/useNavigationKey.ts
src/components/database/components/database-row/DeleteRowConfirm.tsx
src/components/database/components/property/PropertyProfile.tsx
src/components/database/components/property/select/useOptionDragContext.ts
src/components/database/fullcalendar/hooks/useCalendarHandlers.ts
src/components/database/fullcalendar/hooks/useCurrentTimeIndicator.ts
src/components/editor/CollaborativeEditor.tsx
src/components/editor/components/blocks/database/DatabaseBlock.tsx
src/components/editor/components/drag-drop/handleBlockDrop.ts
src/components/editor/plugins/withInsertText.ts
src/components/editor/utils/fragment.ts
src/components/ws/useAppflowyWebSocket.ts

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

Copy link

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey there - I've reviewed your changes and they look great!

Prompt for AI Agents
Please address the comments from this code review:

## Individual Comments

### Comment 1
<location> `src/application/awareness/dispatch.ts:50-56` </location>
<code_context>
  const dispatchUser = useCallback(
    (userParams: UserAwarenessParams) => {
      if (!awareness) return;

      const metadata: AwarenessMetadata = {
        user_name: userParams.user_name || '',
        cursor_color: userParams.cursor_color,
        selection_color: userParams.selection_color,
        user_avatar: userParams.user_avatar || '',
      };

      const awarenessState: AwarenessState = {
        version: 1,
        timestamp: dayjs().unix(),
        user: {
          uid: userParams.uid,
          device_id: userParams.device_id,
        },
        metadata: JSON.stringify(metadata),
      };

      awareness.setLocalState(awarenessState);

      // Log successful user awareness dispatch
      Log.debug('📡 User awareness dispatched:', awarenessState);
    },
    [awareness]
  );

  return dispatchUser;

</code_context>

<issue_to_address>
**suggestion (code-quality):** Inline variable that is immediately returned ([`inline-immediately-returned-variable`](https://docs.sourcery.ai/Reference/Rules-and-In-Line-Suggestions/TypeScript/Default-Rules/inline-immediately-returned-variable))

```suggestion
  return useCallback(
      (userParams: UserAwarenessParams) => {
        if (!awareness) return;

        const metadata: AwarenessMetadata = {
          user_name: userParams.user_name || '',
          cursor_color: userParams.cursor_color,
          selection_color: userParams.selection_color,
          user_avatar: userParams.user_avatar || '',
        };

        const awarenessState: AwarenessState = {
          version: 1,
          timestamp: dayjs().unix(),
          user: {
            uid: userParams.uid,
            device_id: userParams.device_id,
          },
          metadata: JSON.stringify(metadata),
        };

        awareness.setLocalState(awarenessState);

        // Log successful user awareness dispatch
        Log.debug('📡 User awareness dispatched:', awarenessState);
      },
      [awareness]
    );

```

<br/><details><summary>Explanation</summary>Something that we often see in people's code is assigning to a result variable
and then immediately returning it.

Returning the result directly shortens the code and removes an unnecessary
variable, reducing the mental load of reading the function.

Where intermediate variables can be useful is if they then get used as a
parameter or a condition, and the name can act like a comment on what the
variable represents. In the case where you're returning it from a function, the
function name is there to tell you what the result is, so the variable name
is unnecessary.
</details>
</issue_to_address>

### Comment 2
<location> `src/application/awareness/selector.ts:121-127` </location>
<code_context>
  const cursorsWithBaseRange = useMemo(() => {
    if (!cursors.length || !editor || !editor.children[0]) return [];

    const result = cursors.map((cursor) => {
      const baseRange = convertAwarenessSelection(cursor.selection, editor.children);

      return {
        ...cursor,
        baseRange,
      };
    });

    Log.debug('🎯 Final cursors array:', result);
    return result;
  }, [cursors, editor]);

  return cursorsWithBaseRange;

</code_context>

<issue_to_address>
**suggestion (code-quality):** Inline variable that is immediately returned ([`inline-immediately-returned-variable`](https://docs.sourcery.ai/Reference/Rules-and-In-Line-Suggestions/TypeScript/Default-Rules/inline-immediately-returned-variable))

```suggestion
  return useMemo(() => {
      if (!cursors.length || !editor || !editor.children[0]) return [];

      const result = cursors.map((cursor) => {
        const baseRange = convertAwarenessSelection(cursor.selection, editor.children);

        return {
          ...cursor,
          baseRange,
        };
      });

      Log.debug('🎯 Final cursors array:', result);
      return result;
    }, [cursors, editor]);

```

<br/><details><summary>Explanation</summary>Something that we often see in people's code is assigning to a result variable
and then immediately returning it.

Returning the result directly shortens the code and removes an unnecessary
variable, reducing the mental load of reading the function.

Where intermediate variables can be useful is if they then get used as a
parameter or a condition, and the name can act like a comment on what the
variable represents. In the case where you're returning it from a function, the
function name is there to tell you what the result is, so the variable name
is unnecessary.
</details>
</issue_to_address>

### Comment 3
<location> `src/components/database/components/drag-and-drop/useDragContext.ts:50-54` </location>
<code_context>

</code_context>

<issue_to_address>
**issue (code-quality):** Avoid function declarations, favouring function assignment expressions, inside blocks. ([`avoid-function-declarations-in-blocks`](https://docs.sourcery.ai/Reference/Rules-and-In-Line-Suggestions/TypeScript/Default-Rules/avoid-function-declarations-in-blocks))

<details><summary>Explanation</summary>Function declarations may be hoisted in Javascript, but the behaviour is inconsistent between browsers.
Hoisting is generally confusing and should be avoided. Rather than using function declarations inside blocks, you
should use function expressions, which create functions in-scope.
</details>
</issue_to_address>

### Comment 4
<location> `src/components/database/components/grid/drag-and-drop/GridDragContext.tsx:52-56` </location>
<code_context>

</code_context>

<issue_to_address>
**issue (code-quality):** Avoid function declarations, favouring function assignment expressions, inside blocks. ([`avoid-function-declarations-in-blocks`](https://docs.sourcery.ai/Reference/Rules-and-In-Line-Suggestions/TypeScript/Default-Rules/avoid-function-declarations-in-blocks))

<details><summary>Explanation</summary>Function declarations may be hoisted in Javascript, but the behaviour is inconsistent between browsers.
Hoisting is generally confusing and should be avoided. Rather than using function declarations inside blocks, you
should use function expressions, which create functions in-scope.
</details>
</issue_to_address>

### Comment 5
<location> `src/components/database/components/grid/drag-and-drop/GridDragContext.tsx:74-78` </location>
<code_context>

</code_context>

<issue_to_address>
**issue (code-quality):** Avoid function declarations, favouring function assignment expressions, inside blocks. ([`avoid-function-declarations-in-blocks`](https://docs.sourcery.ai/Reference/Rules-and-In-Line-Suggestions/TypeScript/Default-Rules/avoid-function-declarations-in-blocks))

<details><summary>Explanation</summary>Function declarations may be hoisted in Javascript, but the behaviour is inconsistent between browsers.
Hoisting is generally confusing and should be avoided. Rather than using function declarations inside blocks, you
should use function expressions, which create functions in-scope.
</details>
</issue_to_address>

### Comment 6
<location> `src/components/database/components/property/select/useOptionDragContext.ts:53-57` </location>
<code_context>

</code_context>

<issue_to_address>
**issue (code-quality):** Avoid function declarations, favouring function assignment expressions, inside blocks. ([`avoid-function-declarations-in-blocks`](https://docs.sourcery.ai/Reference/Rules-and-In-Line-Suggestions/TypeScript/Default-Rules/avoid-function-declarations-in-blocks))

<details><summary>Explanation</summary>Function declarations may be hoisted in Javascript, but the behaviour is inconsistent between browsers.
Hoisting is generally confusing and should be avoided. Rather than using function declarations inside blocks, you
should use function expressions, which create functions in-scope.
</details>
</issue_to_address>

### Comment 7
<location> `src/components/database/components/settings/usePropertyDragContext.ts:58-62` </location>
<code_context>

</code_context>

<issue_to_address>
**issue (code-quality):** Avoid function declarations, favouring function assignment expressions, inside blocks. ([`avoid-function-declarations-in-blocks`](https://docs.sourcery.ai/Reference/Rules-and-In-Line-Suggestions/TypeScript/Default-Rules/avoid-function-declarations-in-blocks))

<details><summary>Explanation</summary>Function declarations may be hoisted in Javascript, but the behaviour is inconsistent between browsers.
Hoisting is generally confusing and should be avoided. Rather than using function declarations inside blocks, you
should use function expressions, which create functions in-scope.
</details>
</issue_to_address>

### Comment 8
<location> `src/components/editor/components/blocks/database/hooks/useRetryFunction.ts:37-43` </location>
<code_context>
  const retryFunction = useCallback(
    async (...args: T): Promise<R> => {
      let attempt = 1;

      const executeWithRetry = async (): Promise<R> => {
        try {
          if (!fn) {
            throw new Error('Function not available');
          }

          const result = await fn(...args);

          if (!result) {
            throw new Error('No result returned');
          }

          return result;
        } catch (error) {
          if (attempt < RETRY_CONFIG.maxAttempts) {
            const delay = RETRY_CONFIG.getRetryDelay(attempt);

            Log.debug(`[useRetryFunction] Retry attempt ${attempt} after ${delay}ms`, error);
            attempt++;
            await new Promise(resolve => setTimeout(resolve, delay));

            return executeWithRetry();
          } else {
            console.error(`[useRetryFunction] All ${RETRY_CONFIG.maxAttempts} attempts failed`, error);
            onError();
            throw error;
          }
        }
      };

      return executeWithRetry();
    },
    [fn, onError]
  );

  return retryFunction;

</code_context>

<issue_to_address>
**suggestion (code-quality):** Inline variable that is immediately returned ([`inline-immediately-returned-variable`](https://docs.sourcery.ai/Reference/Rules-and-In-Line-Suggestions/TypeScript/Default-Rules/inline-immediately-returned-variable))

```suggestion
  return useCallback(
      async (...args: T): Promise<R> => {
        let attempt = 1;

        const executeWithRetry = async (): Promise<R> => {
          try {
            if (!fn) {
              throw new Error('Function not available');
            }

            const result = await fn(...args);

            if (!result) {
              throw new Error('No result returned');
            }

            return result;
          } catch (error) {
            if (attempt < RETRY_CONFIG.maxAttempts) {
              const delay = RETRY_CONFIG.getRetryDelay(attempt);

              Log.debug(`[useRetryFunction] Retry attempt ${attempt} after ${delay}ms`, error);
              attempt++;
              await new Promise(resolve => setTimeout(resolve, delay));

              return executeWithRetry();
            } else {
              console.error(`[useRetryFunction] All ${RETRY_CONFIG.maxAttempts} attempts failed`, error);
              onError();
              throw error;
            }
          }
        };

        return executeWithRetry();
      },
      [fn, onError]
    );

```

<br/><details><summary>Explanation</summary>Something that we often see in people's code is assigning to a result variable
and then immediately returning it.

Returning the result directly shortens the code and removes an unnecessary
variable, reducing the mental load of reading the function.

Where intermediate variables can be useful is if they then get used as a
parameter or a condition, and the name can act like a comment on what the
variable represents. In the case where you're returning it from a function, the
function name is there to tell you what the result is, so the variable name
is unnecessary.
</details>
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

@appflowy appflowy merged commit a3945b0 into main Dec 2, 2025
11 of 12 checks passed
@appflowy appflowy deleted the console_log2 branch December 2, 2025 08:49
josue693 pushed a commit to josue693/AppFlowy-Web that referenced this pull request Dec 21, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants