فهرست منبع

Merge pull request #30237 from overleaf/ae-workbench-popover

Add a popover to the AI assistant rail button

GitOrigin-RevId: 5bc141ba10ef0bc798ab79a847d73804d60353d6
Mathias Jakobsen 8 ماه پیش
والد
کامیت
efe7cf0064

+ 1 - 0
services/web/app/src/Features/Tutorial/TutorialController.mjs

@@ -29,6 +29,7 @@ const VALID_KEYS = [
   'new-editor-intro',
   'new-editor-intro-2',
   'old-editor-warning-tooltip',
+  'workbench-rail-popover',
 ]
 
 async function completeTutorial(req, res, next) {

+ 1 - 0
services/web/config/settings.defaults.js

@@ -1048,6 +1048,7 @@ module.exports = {
     errorLogsComponents: [],
     referenceIndices: [],
     railEntries: [],
+    railPopovers: [],
   },
 
   moduleImportSequence: [

+ 2 - 2
services/web/frontend/js/features/ide-redesign/components/rail/rail-overflow-dropdown.tsx

@@ -2,7 +2,7 @@ import { DropdownMenu } from '@/shared/components/dropdown/dropdown-menu'
 import { RailTabKey } from '../../contexts/rail-context'
 import { RailElement } from '../../utils/rail-types'
 import RailTab from './rail-tab'
-import { shouldIncludeRailTab } from '../../utils/rail-utils'
+import { shouldIncludeElement } from '../../utils/rail-utils'
 
 export default function RailOverflowDropdown({
   tabs,
@@ -16,7 +16,7 @@ export default function RailOverflowDropdown({
   return (
     <DropdownMenu className="ide-rail-overflow-dropdown">
       {tabs
-        .filter(shouldIncludeRailTab)
+        .filter(shouldIncludeElement)
         .map(({ icon, key, indicator, title, disabled }) => (
           <RailTab
             open={isOpen && selectedTab === key}

+ 2 - 2
services/web/frontend/js/features/ide-redesign/components/rail/rail-panel.tsx

@@ -6,7 +6,7 @@ import usePreviousValue from '@/shared/hooks/use-previous-value'
 import { HistorySidebar } from '@/features/ide-react/components/history-sidebar'
 import { Tab } from 'react-bootstrap'
 import { RailElement } from '../../utils/rail-types'
-import { shouldIncludeRailTab } from '../../utils/rail-utils'
+import { shouldIncludeElement } from '../../utils/rail-utils'
 
 export default function RailPanel({
   isReviewPanelOpen,
@@ -53,7 +53,7 @@ export default function RailPanel({
       >
         <Tab.Content className="ide-rail-tab-content">
           {railTabs
-            .filter(shouldIncludeRailTab)
+            .filter(shouldIncludeElement)
             .map(({ key, component, mountOnFirstLoad }) => (
               <Tab.Pane
                 eventKey={key}

+ 22 - 4
services/web/frontend/js/features/ide-redesign/components/rail/rail.tsx

@@ -1,4 +1,4 @@
-import { useCallback, useEffect, useMemo, useRef } from 'react'
+import { FC, RefObject, useCallback, useEffect, useMemo, useRef } from 'react'
 import { useTranslation } from 'react-i18next'
 import { Nav, TabContainer } from 'react-bootstrap'
 import { useLayoutContext } from '@/shared/context/layout-context'
@@ -30,7 +30,7 @@ import EditorTourRailTooltip from '../editor-tour/editor-tour-rail-tooltip'
 import importOverleafModules from '../../../../../macros/import-overleaf-module.macro'
 import EditorTourThemeTooltip from '../editor-tour/editor-tour-theme-tooltip'
 import EditorTourSwitchBackTooltip from '../editor-tour/editor-tour-switch-back-tooltip'
-import { shouldIncludeRailTab } from '../../utils/rail-utils'
+import { shouldIncludeElement } from '../../utils/rail-utils'
 
 const moduleRailEntries = (
   importOverleafModules('railEntries') as {
@@ -38,6 +38,19 @@ const moduleRailEntries = (
     path: string
   }[]
 ).map(({ import: { default: element } }) => element)
+const moduleRailPopovers = (
+  importOverleafModules('railPopovers') as {
+    import: {
+      default: {
+        key: string
+        Component: FC<{ ref: RefObject<HTMLAnchorElement> }>
+        ref: RefObject<HTMLAnchorElement>
+        hide: boolean | (() => boolean)
+      }
+    }
+    path: string
+  }[]
+).map(({ import: { default: element } }) => element)
 
 export const RailLayout = () => {
   const { sendEvent } = useEditorAnalytics()
@@ -175,7 +188,7 @@ export const RailLayout = () => {
 
   useEffect(() => {
     const validTabKeys = railTabs
-      .filter(shouldIncludeRailTab)
+      .filter(shouldIncludeElement)
       .map(tab => tab.key)
     if (!validTabKeys.includes(selectedTab) && isOpen) {
       // If the selected tab is no longer valid (e.g. due to permissions changes),
@@ -225,7 +238,7 @@ export const RailLayout = () => {
         <Nav activeKey={selectedTab} className="ide-rail-tabs-nav">
           <div className="ide-rail-tabs-wrapper" ref={tabWrapperRef}>
             {tabsInRail
-              .filter(shouldIncludeRailTab)
+              .filter(shouldIncludeElement)
               .map(({ icon, key, indicator, title, disabled, ref }) => (
                 <RailTab
                   open={isOpen && selectedTab === key}
@@ -254,6 +267,11 @@ export const RailLayout = () => {
       <EditorTourRailTooltip target={fileTreeRef.current} />
       <EditorTourThemeTooltip target={settingsRef.current} />
       <EditorTourSwitchBackTooltip target={settingsRef.current} />
+      {moduleRailPopovers
+        .filter(shouldIncludeElement)
+        .map(({ key, Component, ref }) => (
+          <Component key={key} ref={ref} />
+        ))}
       <RailPanel
         isReviewPanelOpen={isReviewPanelOpen}
         isHistoryView={isHistoryView}

+ 3 - 0
services/web/frontend/js/features/ide-redesign/contexts/new-editor-tour-context.tsx

@@ -15,6 +15,7 @@ const NewEditorTourContext = createContext<
       stage: NewEditorTourStage
       stageNumber: number
       totalStages: number
+      isShowing: boolean
       shouldShowTourStage: (tourStage: NewEditorTourStage) => boolean
       startTour: () => void
       goToNextStage: () => void
@@ -83,6 +84,7 @@ export const NewEditorTourProvider: FC<React.PropsWithChildren> = ({
       goToNextStage,
       finishTour,
       dismissTour,
+      isShowing: showTour,
     }),
     [
       stage,
@@ -93,6 +95,7 @@ export const NewEditorTourProvider: FC<React.PropsWithChildren> = ({
       goToNextStage,
       finishTour,
       dismissTour,
+      showTour,
     ]
   )
 

+ 5 - 3
services/web/frontend/js/features/ide-redesign/utils/rail-utils.ts

@@ -1,6 +1,8 @@
-import { RailElement } from './rail-types'
-
-export function shouldIncludeRailTab({ hide }: RailElement): boolean {
+export function shouldIncludeElement({
+  hide,
+}: {
+  hide?: boolean | (() => boolean)
+}): boolean {
   if (typeof hide === 'function') {
     return !hide()
   }