From 1a7e15a8255f6d02cae189c10b9e5b406153e029 Mon Sep 17 00:00:00 2001 From: Anmol Singh Bhatia Date: Wed, 3 Dec 2025 19:37:58 +0530 Subject: [PATCH 1/5] chore: app rail context added --- apps/web/core/lib/app-rail/context.tsx | 25 ++++++++++++++ apps/web/core/lib/app-rail/index.ts | 3 ++ apps/web/core/lib/app-rail/provider.tsx | 45 +++++++++++++++++++++++++ apps/web/core/lib/app-rail/types.ts | 22 ++++++++++++ 4 files changed, 95 insertions(+) create mode 100644 apps/web/core/lib/app-rail/context.tsx create mode 100644 apps/web/core/lib/app-rail/index.ts create mode 100644 apps/web/core/lib/app-rail/provider.tsx create mode 100644 apps/web/core/lib/app-rail/types.ts diff --git a/apps/web/core/lib/app-rail/context.tsx b/apps/web/core/lib/app-rail/context.tsx new file mode 100644 index 00000000000..b1625af3639 --- /dev/null +++ b/apps/web/core/lib/app-rail/context.tsx @@ -0,0 +1,25 @@ +"use client"; + +import { createContext, useContext } from "react"; +import type { IAppRailVisibilityContext } from "./types"; + +/** + * Context for app-rail visibility control + * Provides access to app rail enabled state, collapse state, and toggle function + */ +export const AppRailVisibilityContext = createContext(undefined); + +/** + * Hook to consume the AppRailVisibilityContext + * Must be used within an AppRailVisibilityProvider + * + * @returns The app rail visibility context + * @throws Error if used outside of AppRailVisibilityProvider + */ +export const useAppRailVisibility = (): IAppRailVisibilityContext => { + const context = useContext(AppRailVisibilityContext); + if (context === undefined) { + throw new Error("useAppRailVisibility must be used within AppRailVisibilityProvider"); + } + return context; +}; diff --git a/apps/web/core/lib/app-rail/index.ts b/apps/web/core/lib/app-rail/index.ts new file mode 100644 index 00000000000..053a94f0c6b --- /dev/null +++ b/apps/web/core/lib/app-rail/index.ts @@ -0,0 +1,3 @@ +export * from "./context"; +export * from "./provider"; +export * from "./types"; diff --git a/apps/web/core/lib/app-rail/provider.tsx b/apps/web/core/lib/app-rail/provider.tsx new file mode 100644 index 00000000000..5659f2f6f64 --- /dev/null +++ b/apps/web/core/lib/app-rail/provider.tsx @@ -0,0 +1,45 @@ +"use client"; + +import React, { useCallback, useMemo } from "react"; +import { observer } from "mobx-react"; +import { useParams } from "next/navigation"; +import useLocalStorage from "@/hooks/use-local-storage"; +import { AppRailVisibilityContext } from "./context"; +import type { IAppRailVisibilityContext } from "./types"; + +interface AppRailVisibilityProviderProps { + children: React.ReactNode; +} + +/** + * AppRailVisibilityProvider - manages app rail visibility state + * The app rail is always available, but can be collapsed by the user + */ +export const AppRailVisibilityProvider = observer(({ children }: AppRailVisibilityProviderProps) => { + // router + const { workspaceSlug } = useParams(); + + // User preference from localStorage + const { storedValue: isCollapsed, setValue: setIsCollapsed } = useLocalStorage( + `APP_RAIL_${workspaceSlug}`, + false // Default: not collapsed (app rail visible) + ); + + const toggleAppRail = useCallback(() => { + setIsCollapsed(!isCollapsed); + }, [isCollapsed, setIsCollapsed]); + + // Compute final visibility: enabled and not collapsed + const shouldRenderAppRail = !isCollapsed; + + const value: IAppRailVisibilityContext = useMemo( + () => ({ + isCollapsed: isCollapsed ?? false, + shouldRenderAppRail, + toggleAppRail, + }), + [isCollapsed, shouldRenderAppRail, toggleAppRail] + ); + + return {children}; +}); diff --git a/apps/web/core/lib/app-rail/types.ts b/apps/web/core/lib/app-rail/types.ts new file mode 100644 index 00000000000..59ccf7e8208 --- /dev/null +++ b/apps/web/core/lib/app-rail/types.ts @@ -0,0 +1,22 @@ +/** + * Type definitions for app-rail visibility context + */ + +export interface IAppRailVisibilityContext { + /** + * Whether the app rail is collapsed (user preference from localStorage) + */ + isCollapsed: boolean; + + /** + * Computed property: whether the app rail should actually render + * True only if isEnabled && !isCollapsed + */ + shouldRenderAppRail: boolean; + + /** + * Toggle the collapse state of the app rail + */ + toggleAppRail: () => void; +} + From 8667f12879032a51b4da804d7028dbc8165ebd76 Mon Sep 17 00:00:00 2001 From: Anmol Singh Bhatia Date: Wed, 3 Dec 2025 19:40:07 +0530 Subject: [PATCH 2/5] chore: dock/undock app rail implementation --- apps/web/app/(all)/[workspaceSlug]/layout.tsx | 9 ++++++--- .../ce/components/workspace/content-wrapper.tsx | 14 +++++++++++--- .../workspace/sidebar/user-menu-root.tsx | 14 +++++++++++++- 3 files changed, 30 insertions(+), 7 deletions(-) diff --git a/apps/web/app/(all)/[workspaceSlug]/layout.tsx b/apps/web/app/(all)/[workspaceSlug]/layout.tsx index 65ad48f7f38..027e17844cd 100644 --- a/apps/web/app/(all)/[workspaceSlug]/layout.tsx +++ b/apps/web/app/(all)/[workspaceSlug]/layout.tsx @@ -1,4 +1,5 @@ import { Outlet } from "react-router"; +import { AppRailVisibilityProvider } from "@/lib/app-rail"; import { AuthenticationWrapper } from "@/lib/wrappers/authentication-wrapper"; import { WorkspaceContentWrapper } from "@/plane-web/components/workspace/content-wrapper"; import { WorkspaceAuthWrapper } from "@/plane-web/layouts/workspace-wrapper"; @@ -7,9 +8,11 @@ export default function WorkspaceLayout() { return ( - - - + + + + + ); diff --git a/apps/web/ce/components/workspace/content-wrapper.tsx b/apps/web/ce/components/workspace/content-wrapper.tsx index 462fcd584a1..0ebe7a88627 100644 --- a/apps/web/ce/components/workspace/content-wrapper.tsx +++ b/apps/web/ce/components/workspace/content-wrapper.tsx @@ -3,7 +3,8 @@ import { observer } from "mobx-react"; // plane imports import { cn } from "@plane/utils"; import { AppRailRoot } from "@/components/navigation"; -// plane web imports +import { useAppRailVisibility } from "@/lib/app-rail"; +// local imports import { TopNavigationRoot } from "../navigations"; export const WorkspaceContentWrapper = observer(function WorkspaceContentWrapper({ @@ -11,14 +12,21 @@ export const WorkspaceContentWrapper = observer(function WorkspaceContentWrapper }: { children: React.ReactNode; }) { + // Use the context to determine if app rail should render + const { shouldRenderAppRail } = useAppRailVisibility(); + return (
- + {/* Conditionally render AppRailRoot based on context */} + {shouldRenderAppRail && }
{children} diff --git a/apps/web/core/components/workspace/sidebar/user-menu-root.tsx b/apps/web/core/components/workspace/sidebar/user-menu-root.tsx index e930396dd7a..9d4c753334d 100644 --- a/apps/web/core/components/workspace/sidebar/user-menu-root.tsx +++ b/apps/web/core/components/workspace/sidebar/user-menu-root.tsx @@ -3,7 +3,7 @@ import { observer } from "mobx-react"; import Link from "next/link"; import { useParams } from "next/navigation"; // icons -import { LogOut, Settings } from "lucide-react"; +import { LogOut, Settings, PanelLeft, PanelLeftClose } from "lucide-react"; // plane imports import { GOD_MODE_URL } from "@plane/constants"; import { useTranslation } from "@plane/i18n"; @@ -14,6 +14,7 @@ import { getFileURL } from "@plane/utils"; import { AppSidebarItem } from "@/components/sidebar/sidebar-item"; import { useAppTheme } from "@/hooks/store/use-app-theme"; import { useUser } from "@/hooks/store/user"; +import { useAppRailVisibility } from "@/lib/app-rail"; type Props = { size?: "xs" | "sm" | "md"; @@ -26,6 +27,7 @@ export const UserMenuRoot = observer(function UserMenuRoot(props: Props) { const { toggleAnySidebarDropdown } = useAppTheme(); const { data: currentUser } = useUser(); const { signOut } = useUser(); + const { isCollapsed, toggleAppRail } = useAppRailVisibility(); // derived values const isUserInstanceAdmin = false; // translation @@ -84,6 +86,16 @@ export const UserMenuRoot = observer(function UserMenuRoot(props: Props) {
+ +
+ {isCollapsed ? ( + + ) : ( + + )} + {isCollapsed ? "Show app rail" : "Hide app rail"} +
+
From 099668fd7ba3c81b69850a5b1148f608b05bc608 Mon Sep 17 00:00:00 2001 From: Anmol Singh Bhatia Date: Thu, 4 Dec 2025 15:23:27 +0530 Subject: [PATCH 3/5] chore: refactor --- apps/web/app/(all)/[workspaceSlug]/layout.tsx | 2 +- apps/web/ce/hooks/app-rail/index.ts | 1 + apps/web/ce/hooks/app-rail/provider.tsx | 17 +++++++++++++ .../workspace/sidebar/help-section/root.tsx | 2 +- .../workspace/sidebar/user-menu-root.tsx | 24 ++++++++++--------- .../workspace/sidebar/workspace-menu-root.tsx | 2 +- apps/web/core/lib/app-rail/provider.tsx | 11 +++++---- apps/web/core/lib/app-rail/types.ts | 5 ++++ apps/web/ee/hooks/app-rail/index.ts | 1 + 9 files changed, 46 insertions(+), 19 deletions(-) create mode 100644 apps/web/ce/hooks/app-rail/index.ts create mode 100644 apps/web/ce/hooks/app-rail/provider.tsx create mode 100644 apps/web/ee/hooks/app-rail/index.ts diff --git a/apps/web/app/(all)/[workspaceSlug]/layout.tsx b/apps/web/app/(all)/[workspaceSlug]/layout.tsx index 027e17844cd..0e489644d4a 100644 --- a/apps/web/app/(all)/[workspaceSlug]/layout.tsx +++ b/apps/web/app/(all)/[workspaceSlug]/layout.tsx @@ -1,7 +1,7 @@ import { Outlet } from "react-router"; -import { AppRailVisibilityProvider } from "@/lib/app-rail"; import { AuthenticationWrapper } from "@/lib/wrappers/authentication-wrapper"; import { WorkspaceContentWrapper } from "@/plane-web/components/workspace/content-wrapper"; +import { AppRailVisibilityProvider } from "@/plane-web/hooks/app-rail"; import { WorkspaceAuthWrapper } from "@/plane-web/layouts/workspace-wrapper"; export default function WorkspaceLayout() { diff --git a/apps/web/ce/hooks/app-rail/index.ts b/apps/web/ce/hooks/app-rail/index.ts new file mode 100644 index 00000000000..1a8f850f5f8 --- /dev/null +++ b/apps/web/ce/hooks/app-rail/index.ts @@ -0,0 +1 @@ +export * from "./provider"; diff --git a/apps/web/ce/hooks/app-rail/provider.tsx b/apps/web/ce/hooks/app-rail/provider.tsx new file mode 100644 index 00000000000..f53d7d2eb53 --- /dev/null +++ b/apps/web/ce/hooks/app-rail/provider.tsx @@ -0,0 +1,17 @@ +"use client"; + +import React from "react"; +import { observer } from "mobx-react"; +import { AppRailVisibilityProvider as CoreProvider } from "@/lib/app-rail"; + +interface AppRailVisibilityProviderProps { + children: React.ReactNode; +} + +/** + * CE AppRailVisibilityProvider + * Wraps core provider with isEnabled hardcoded to false + */ +export const AppRailVisibilityProvider = observer(({ children }: AppRailVisibilityProviderProps) => ( + {children} +)); diff --git a/apps/web/core/components/workspace/sidebar/help-section/root.tsx b/apps/web/core/components/workspace/sidebar/help-section/root.tsx index 0fb0b31783b..c746b084e70 100644 --- a/apps/web/core/components/workspace/sidebar/help-section/root.tsx +++ b/apps/web/core/components/workspace/sidebar/help-section/root.tsx @@ -32,7 +32,7 @@ export const HelpMenuRoot = observer(function HelpMenuRoot() { , + icon: , isActive: isNeedHelpOpen, }} /> diff --git a/apps/web/core/components/workspace/sidebar/user-menu-root.tsx b/apps/web/core/components/workspace/sidebar/user-menu-root.tsx index 9d4c753334d..505c0539c67 100644 --- a/apps/web/core/components/workspace/sidebar/user-menu-root.tsx +++ b/apps/web/core/components/workspace/sidebar/user-menu-root.tsx @@ -27,7 +27,7 @@ export const UserMenuRoot = observer(function UserMenuRoot(props: Props) { const { toggleAnySidebarDropdown } = useAppTheme(); const { data: currentUser } = useUser(); const { signOut } = useUser(); - const { isCollapsed, toggleAppRail } = useAppRailVisibility(); + const { isEnabled, isCollapsed, toggleAppRail } = useAppRailVisibility(); // derived values const isUserInstanceAdmin = false; // translation @@ -86,16 +86,18 @@ export const UserMenuRoot = observer(function UserMenuRoot(props: Props) {
- -
- {isCollapsed ? ( - - ) : ( - - )} - {isCollapsed ? "Show app rail" : "Hide app rail"} -
-
+ {isEnabled && ( + +
+ {isCollapsed ? ( + + ) : ( + + )} + {isCollapsed ? "Show app rail" : "Hide app rail"} +
+
+ )}
diff --git a/apps/web/core/components/workspace/sidebar/workspace-menu-root.tsx b/apps/web/core/components/workspace/sidebar/workspace-menu-root.tsx index 51071d52e1c..29630324164 100644 --- a/apps/web/core/components/workspace/sidebar/workspace-menu-root.tsx +++ b/apps/web/core/components/workspace/sidebar/workspace-menu-root.tsx @@ -118,7 +118,7 @@ export const WorkspaceMenuRoot = observer(function WorkspaceMenuRoot(props: Work

{activeWorkspace?.name ?? t("loading")} diff --git a/apps/web/core/lib/app-rail/provider.tsx b/apps/web/core/lib/app-rail/provider.tsx index 5659f2f6f64..1785a07c57b 100644 --- a/apps/web/core/lib/app-rail/provider.tsx +++ b/apps/web/core/lib/app-rail/provider.tsx @@ -9,14 +9,14 @@ import type { IAppRailVisibilityContext } from "./types"; interface AppRailVisibilityProviderProps { children: React.ReactNode; + isEnabled?: boolean; // Allow override, default false } /** * AppRailVisibilityProvider - manages app rail visibility state - * The app rail is always available, but can be collapsed by the user + * Base provider that accepts isEnabled as a prop */ -export const AppRailVisibilityProvider = observer(({ children }: AppRailVisibilityProviderProps) => { - // router +export const AppRailVisibilityProvider = observer(({ children, isEnabled = false }: AppRailVisibilityProviderProps) => { const { workspaceSlug } = useParams(); // User preference from localStorage @@ -30,15 +30,16 @@ export const AppRailVisibilityProvider = observer(({ children }: AppRailVisibili }, [isCollapsed, setIsCollapsed]); // Compute final visibility: enabled and not collapsed - const shouldRenderAppRail = !isCollapsed; + const shouldRenderAppRail = isEnabled && !isCollapsed; const value: IAppRailVisibilityContext = useMemo( () => ({ + isEnabled, isCollapsed: isCollapsed ?? false, shouldRenderAppRail, toggleAppRail, }), - [isCollapsed, shouldRenderAppRail, toggleAppRail] + [isEnabled, isCollapsed, shouldRenderAppRail, toggleAppRail] ); return {children}; diff --git a/apps/web/core/lib/app-rail/types.ts b/apps/web/core/lib/app-rail/types.ts index 59ccf7e8208..5b63b5c6ed7 100644 --- a/apps/web/core/lib/app-rail/types.ts +++ b/apps/web/core/lib/app-rail/types.ts @@ -3,6 +3,11 @@ */ export interface IAppRailVisibilityContext { + /** + * Whether the app rail is enabled + */ + isEnabled: boolean; + /** * Whether the app rail is collapsed (user preference from localStorage) */ diff --git a/apps/web/ee/hooks/app-rail/index.ts b/apps/web/ee/hooks/app-rail/index.ts new file mode 100644 index 00000000000..10e2ef3ef39 --- /dev/null +++ b/apps/web/ee/hooks/app-rail/index.ts @@ -0,0 +1 @@ +export * from "ce/hooks/app-rail"; \ No newline at end of file From 3f3243eb5487131d1a1f2a87d80cfbd58ade1ee8 Mon Sep 17 00:00:00 2001 From: Anmol Singh Bhatia Date: Thu, 4 Dec 2025 16:53:52 +0530 Subject: [PATCH 4/5] chore: code refactor --- .../ce/components/app-rail/app-rail-hoc.tsx | 2 +- .../components/navigation/app-rail-root.tsx | 6 ++++++ .../workspace/sidebar/user-menu-root.tsx | 20 +++++++------------ packages/i18n/src/locales/en/translations.ts | 4 ++-- .../propel/src/icons/sub-brand/plane-icon.tsx | 8 +++----- .../propel/src/icons/sub-brand/wiki-icon.tsx | 6 ++---- 6 files changed, 21 insertions(+), 25 deletions(-) diff --git a/apps/web/ce/components/app-rail/app-rail-hoc.tsx b/apps/web/ce/components/app-rail/app-rail-hoc.tsx index 562695dcd8e..89b9e7778fc 100644 --- a/apps/web/ce/components/app-rail/app-rail-hoc.tsx +++ b/apps/web/ce/components/app-rail/app-rail-hoc.tsx @@ -20,7 +20,7 @@ export function withDockItems

(WrappedComponent: Re const dockItems: (AppSidebarItemData & { shouldRender: boolean })[] = [ { label: "Projects", - icon: , + icon: , href: `/${workspaceSlug}/`, isActive: isProjectsPath && !isNotificationsPath, shouldRender: true, diff --git a/apps/web/core/components/navigation/app-rail-root.tsx b/apps/web/core/components/navigation/app-rail-root.tsx index 38b8804843b..864a81a00fb 100644 --- a/apps/web/core/components/navigation/app-rail-root.tsx +++ b/apps/web/core/components/navigation/app-rail-root.tsx @@ -8,6 +8,7 @@ import { cn } from "@plane/utils"; import { AppSidebarItem } from "@/components/sidebar/sidebar-item"; // hooks import { useAppRailPreferences } from "@/hooks/use-navigation-preferences"; +import { useAppRailVisibility } from "@/lib/app-rail/context"; // plane web imports import { DesktopSidebarWorkspaceMenu } from "@/plane-web/components/desktop"; // local imports @@ -19,6 +20,7 @@ export const AppRailRoot = observer(() => { const pathname = usePathname(); // preferences const { preferences, updateDisplayMode } = useAppRailPreferences(); + const { isCollapsed, toggleAppRail } = useAppRailVisibility(); const isSettingsPath = pathname.includes(`/${workspaceSlug}/settings`); const showLabel = preferences.displayMode === "icon_with_label"; @@ -70,6 +72,10 @@ export const AppRailRoot = observer(() => { {preferences.displayMode === "icon_with_label" && }

+ + + {isCollapsed ? "Dock App Rail" : "Undock App Rail"} + diff --git a/apps/web/core/components/workspace/sidebar/user-menu-root.tsx b/apps/web/core/components/workspace/sidebar/user-menu-root.tsx index 505c0539c67..6cb7e8813b7 100644 --- a/apps/web/core/components/workspace/sidebar/user-menu-root.tsx +++ b/apps/web/core/components/workspace/sidebar/user-menu-root.tsx @@ -3,7 +3,7 @@ import { observer } from "mobx-react"; import Link from "next/link"; import { useParams } from "next/navigation"; // icons -import { LogOut, Settings, PanelLeft, PanelLeftClose } from "lucide-react"; +import { LogOut, Settings, Settings2 } from "lucide-react"; // plane imports import { GOD_MODE_URL } from "@plane/constants"; import { useTranslation } from "@plane/i18n"; @@ -14,7 +14,6 @@ import { getFileURL } from "@plane/utils"; import { AppSidebarItem } from "@/components/sidebar/sidebar-item"; import { useAppTheme } from "@/hooks/store/use-app-theme"; import { useUser } from "@/hooks/store/user"; -import { useAppRailVisibility } from "@/lib/app-rail"; type Props = { size?: "xs" | "sm" | "md"; @@ -27,7 +26,6 @@ export const UserMenuRoot = observer(function UserMenuRoot(props: Props) { const { toggleAnySidebarDropdown } = useAppTheme(); const { data: currentUser } = useUser(); const { signOut } = useUser(); - const { isEnabled, isCollapsed, toggleAppRail } = useAppRailVisibility(); // derived values const isUserInstanceAdmin = false; // translation @@ -76,7 +74,7 @@ export const UserMenuRoot = observer(function UserMenuRoot(props: Props) { maxHeight="lg" closeOnSelect > -
+
{currentUser?.email} @@ -86,18 +84,14 @@ export const UserMenuRoot = observer(function UserMenuRoot(props: Props) {
- {isEnabled && ( - + +
- {isCollapsed ? ( - - ) : ( - - )} - {isCollapsed ? "Show app rail" : "Hide app rail"} + + Preferences
- )} +
diff --git a/packages/i18n/src/locales/en/translations.ts b/packages/i18n/src/locales/en/translations.ts index b5b186a4331..a6a991f72f9 100644 --- a/packages/i18n/src/locales/en/translations.ts +++ b/packages/i18n/src/locales/en/translations.ts @@ -2699,8 +2699,8 @@ export default { // Navigation customization customize_navigation: "Customize navigation", personal: "Personal", - accordion_navigation_control: "Accordion navigation control", - horizontal_navigation_bar: "Horizontal navigation bar", + accordion_navigation_control: "Accordion sidebar navigation", + horizontal_navigation_bar: "Tabbed Navigation", show_limited_projects_on_sidebar: "Show limited projects on sidebar", enter_number_of_projects: "Enter number of projects", pin: "Pin", diff --git a/packages/propel/src/icons/sub-brand/plane-icon.tsx b/packages/propel/src/icons/sub-brand/plane-icon.tsx index 01d8fe4e420..978cc1e726d 100644 --- a/packages/propel/src/icons/sub-brand/plane-icon.tsx +++ b/packages/propel/src/icons/sub-brand/plane-icon.tsx @@ -4,16 +4,14 @@ import { IconWrapper } from "../icon-wrapper"; import type { ISvgIcons } from "../type"; export function PlaneNewIcon({ color = "currentColor", ...rest }: ISvgIcons) { - const clipPathId = React.useId(); - return ( - + diff --git a/packages/propel/src/icons/sub-brand/wiki-icon.tsx b/packages/propel/src/icons/sub-brand/wiki-icon.tsx index c6da52c03a5..d062f448bc8 100644 --- a/packages/propel/src/icons/sub-brand/wiki-icon.tsx +++ b/packages/propel/src/icons/sub-brand/wiki-icon.tsx @@ -4,12 +4,10 @@ import { IconWrapper } from "../icon-wrapper"; import type { ISvgIcons } from "../type"; export function WikiIcon({ color = "currentColor", ...rest }: ISvgIcons) { - const clipPathId = React.useId(); - return ( - + From 13af6d282e056913ab5eed8c8b65ca8be959ebdd Mon Sep 17 00:00:00 2001 From: Anmol Singh Bhatia Date: Thu, 4 Dec 2025 17:18:36 +0530 Subject: [PATCH 5/5] chore: code refactor --- apps/web/core/lib/app-rail/types.ts | 1 - apps/web/ee/hooks/app-rail/index.ts | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/apps/web/core/lib/app-rail/types.ts b/apps/web/core/lib/app-rail/types.ts index 5b63b5c6ed7..36dbcb129e4 100644 --- a/apps/web/core/lib/app-rail/types.ts +++ b/apps/web/core/lib/app-rail/types.ts @@ -24,4 +24,3 @@ export interface IAppRailVisibilityContext { */ toggleAppRail: () => void; } - diff --git a/apps/web/ee/hooks/app-rail/index.ts b/apps/web/ee/hooks/app-rail/index.ts index 10e2ef3ef39..0bfcd74e046 100644 --- a/apps/web/ee/hooks/app-rail/index.ts +++ b/apps/web/ee/hooks/app-rail/index.ts @@ -1 +1 @@ -export * from "ce/hooks/app-rail"; \ No newline at end of file +export * from "ce/hooks/app-rail";