DEV Community

Ramu Narasinga
Ramu Narasinga

Posted on • Edited on

LobeChat uses Namespace for action labels in DevTools configuration

In this article, we will look at how the action labels use Namespace in LobeChat devtools. I want to provide a bit of an introduction to the terms such action labels, devtools and how/why they come into the picture.

LobeChat uses Zustand for its state management and has DevTools configured for debugging purposes. When you see DevTools configured, you will have action labels for the Zustand.

Image description

What is action label?

In the set, you will have to provide action label, otherwise this action appears as anonymous in your Redux DevTools.

Example from the documentation

addFish: () => set((state) => ({ fishes: state.fishes + 1 }),
 undefined,
 'jungle/addFish',
 ),
Enter fullscreen mode Exit fullscreen mode

Action name here is a string.

How does LobeChat configure its action label?

Let’s pick this example found in Session Slice action.

switchSession: (sessionId) => {
 if (get().activeId === sessionId) return;

 set({ activeId: sessionId }, false, n(`activeSession/${sessionId}`));
},
Enter fullscreen mode Exit fullscreen mode

Action name here is a function named n. What’s this n function? n is a function returned by a function named setNamespace at line 31.

const n = setNamespace('session');
Enter fullscreen mode Exit fullscreen mode

setNamespace is imported from storeDebug.ts and has the below code:

export const setNamespace = (namespace: string) => {

  return (type: string, payload?: any) => {
   const name = [namespace, type].filter(Boolean).join('/');
     return payload
       ? {
       payload,
       type: name,
     } : name;
   };
};
Enter fullscreen mode Exit fullscreen mode

This returns an arrow function that has two parameters:

  • type: string

  • payload?: any

This below line is interesting.

const name = [namespace, type].filter(Boolean).join('/');
Enter fullscreen mode Exit fullscreen mode

I have never seen this before — applying filter with Boolean. If you were to execute this in your browser’s console using some strings as shown below:

["session", true].filter(Boolean).join('/')

["session", "true"].filter(Boolean).join('/')

["session", "true"].filter(Boolean).join('/')

["session", "switchSession/true/id-123"].filter(Boolean).join('/')

["session", "switchSession/id-123"].filter(Boolean).join('/')
Enter fullscreen mode Exit fullscreen mode

When you paste the above code in the browser’s console, you will find the results shown as in this screenshot below

Image description

I asked ChatGPT to explain this line of code and it has to say this about it:

The line [namespace, type].filter(Boolean).join('/') is used to build a string representing the action name for Zustand's store configuration in LobeChat. Let’s break it down and address why filter(Boolean) is used.

Code Breakdown

[namespace, type]:

This creates an array containing two values: namespace and type.

namespace is likely a string representing a broader category or module.

type represents the specific action within that namespace, e.g., activeSession.

.filter(Boolean):

Filters out any falsy values (e.g., undefined, null, false, or an empty string) from the array.

This ensures the resulting string only includes valid components.

If namespace is not provided (e.g., namespace is undefined or ''), it will not be included in the final string.

.join('/'):

Joins the remaining array elements with a / separator to create a namespaced action name, e.g., namespace/type or just type if namespace is absent.

If the payload exists, an object is returned:

return payload
       ? {
       payload,
       type: name,
     } : name;
   };
Enter fullscreen mode Exit fullscreen mode

Below example is from global/action.ts

toggleChatSideBar: (newValue) => {
    const showChatSideBar =
      typeof newValue === 'boolean' ? newValue : !get().status.showChatSideBar;

    get().updateSystemStatus({ showChatSideBar }, n('toggleAgentPanel', newValue));
},
Enter fullscreen mode Exit fullscreen mode

Conclusion here is action name can be an object or a string.

About me:

Hey, my name is Ramu Narasinga. I study large open-source projects and create content about their codebase architecture and best practices, sharing it through articles, videos.

I am open to work on an interesting project. Send me an email at ramu.narasinga@gmail.com

My Github - https://github.com/ramu-narasinga
My website - https://ramunarasinga.com
My Youtube channel - https://www.youtube.com/@thinkthroo
Learning platform - https://thinkthroo.com
Codebase Architecture - https://app.thinkthroo.com/architecture
Best practices - https://app.thinkthroo.com/best-practices
Production-grade projects - https://app.thinkthroo.com/production-grade-projects

References:

  1. https://github.com/lobehub/lobe-chat/blob/main/src/store/session/slices/session/action.ts#L31C1-L31C35

  2. https://github.com/lobehub/lobe-chat/blob/main/src/utils/storeDebug.ts#L1

  3. https://zustand.docs.pmnd.rs/middlewares/devtools#debugging-a-store

  4. https://zustand.docs.pmnd.rs/middlewares/devtools#all-action-names-are-labeled-as-'anonymous'

Top comments (0)