Просмотр исходного кода

Merge pull request #26527 from overleaf/dp-errors-notification

Add promo for new error logs

GitOrigin-RevId: 68ce79653484dc018be302d753c572c39864c723
David 1 год назад
Родитель
Сommit
6e30a1a32d

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

@@ -15,6 +15,7 @@ const VALID_KEYS = [
   'editor-popup-ux-survey',
   'wf-features-moved',
   'review-mode',
+  'new-error-logs-promo',
 ]
 
 async function completeTutorial(req, res, next) {

+ 1 - 0
services/web/frontend/extracted-translations.json

@@ -539,6 +539,7 @@
   "error": "",
   "error_assist": "",
   "error_log": "",
+  "error_logs_have_had_an_update": "",
   "error_opening_document": "",
   "error_opening_document_detail": "",
   "error_performing_request": "",

+ 59 - 0
services/web/frontend/js/features/ide-redesign/components/error-logs/new-error-logs-promo.tsx

@@ -0,0 +1,59 @@
+import Close from '@/shared/components/close'
+import { useEditorContext } from '@/shared/context/editor-context'
+import useTutorial from '@/shared/hooks/promotions/use-tutorial'
+import { useCallback, useEffect } from 'react'
+import { Overlay, Popover } from 'react-bootstrap'
+import { useTranslation } from 'react-i18next'
+
+const TUTORIAL_KEY = 'new-error-logs-promo'
+const EVENT_DATA = { name: 'new-error-logs-promotion' }
+
+export default function NewErrorLogsPromo({
+  target,
+}: {
+  target: HTMLElement | null
+}) {
+  const { t } = useTranslation()
+
+  const { inactiveTutorials } = useEditorContext()
+  const { showPopup, tryShowingPopup, hideUntilReload, completeTutorial } =
+    useTutorial(TUTORIAL_KEY, EVENT_DATA)
+
+  useEffect(() => {
+    if (!inactiveTutorials.includes(TUTORIAL_KEY)) {
+      tryShowingPopup()
+    }
+  }, [tryShowingPopup, inactiveTutorials])
+
+  const onHide = useCallback(() => {
+    hideUntilReload()
+  }, [hideUntilReload])
+
+  const onClose = useCallback(() => {
+    completeTutorial({
+      action: 'complete',
+      event: 'promo-dismiss',
+    })
+  }, [completeTutorial])
+
+  if (!target) {
+    return null
+  }
+
+  return (
+    <Overlay
+      placement="right"
+      show={showPopup}
+      target={target}
+      rootClose
+      onHide={onHide}
+    >
+      <Popover>
+        <Popover.Body className="new-error-logs-promo">
+          {t('error_logs_have_had_an_update')}
+          <Close variant="dark" onDismiss={onClose} />
+        </Popover.Body>
+      </Popover>
+    </Overlay>
+  )
+}

+ 28 - 17
services/web/frontend/js/features/ide-redesign/components/rail.tsx

@@ -1,4 +1,11 @@
-import { FC, ReactElement, useCallback, useMemo } from 'react'
+import {
+  FC,
+  forwardRef,
+  ReactElement,
+  useCallback,
+  useMemo,
+  useRef,
+} from 'react'
 import { useTranslation } from 'react-i18next'
 import { Nav, NavLink, Tab, TabContainer } from 'react-bootstrap'
 import MaterialIcon, {
@@ -44,6 +51,7 @@ import { useDetachCompileContext as useCompileContext } from '@/shared/context/d
 import OldErrorPane from './error-logs/old-error-pane'
 import { useFeatureFlag } from '@/shared/context/split-test-context'
 import { useSurveyUrl } from '../hooks/use-survey-url'
+import NewErrorLogsPromo from './error-logs/new-error-logs-promo'
 
 type RailElement = {
   icon: AvailableUnfilledIcon
@@ -105,6 +113,8 @@ export const RailLayout = () => {
   const { logEntries } = useCompileContext()
   const errorLogsDisabled = !logEntries
 
+  const errorsTabRef = useRef<HTMLAnchorElement>(null)
+
   const { view, setLeftMenuShown } = useLayoutContext()
 
   const { markMessagesAsRead } = useChatContext()
@@ -230,6 +240,7 @@ export const RailLayout = () => {
             .filter(({ hide }) => !hide)
             .map(({ icon, key, indicator, title, disabled }) => (
               <RailTab
+                ref={key === 'errors' ? errorsTabRef : null}
                 open={isOpen && selectedTab === key}
                 key={key}
                 eventKey={key}
@@ -243,6 +254,7 @@ export const RailLayout = () => {
           {railActions?.map(action => (
             <RailActionElement key={action.key} action={action} />
           ))}
+          {newErrorlogs && <NewErrorLogsPromo target={errorsTabRef.current} />}
         </Nav>
       </div>
       <Panel
@@ -301,21 +313,17 @@ export const RailLayout = () => {
   )
 }
 
-const RailTab = ({
-  icon,
-  eventKey,
-  open,
-  indicator,
-  title,
-  disabled = false,
-}: {
-  icon: AvailableUnfilledIcon
-  eventKey: string
-  open: boolean
-  indicator?: ReactElement
-  title: string
-  disabled?: boolean
-}) => {
+const RailTab = forwardRef<
+  HTMLAnchorElement,
+  {
+    icon: AvailableUnfilledIcon
+    eventKey: string
+    open: boolean
+    indicator?: ReactElement
+    title: string
+    disabled?: boolean
+  }
+>(({ icon, eventKey, open, indicator, title, disabled = false }, ref) => {
   return (
     <OLTooltip
       id={`rail-tab-tooltip-${eventKey}`}
@@ -323,6 +331,7 @@ const RailTab = ({
       overlayProps={{ delay: 0, placement: 'right' }}
     >
       <NavLink
+        ref={ref}
         eventKey={eventKey}
         className={classNames('ide-rail-tab-link', {
           'open-rail': open,
@@ -347,7 +356,9 @@ const RailTab = ({
       </NavLink>
     </OLTooltip>
   )
-}
+})
+
+RailTab.displayName = 'RailTab'
 
 const RailActionElement = ({ action }: { action: RailAction }) => {
   const onActionClick = useCallback(() => {

+ 10 - 0
services/web/frontend/stylesheets/bootstrap-5/pages/editor/rail.scss

@@ -156,3 +156,13 @@ body {
     display: none;
   }
 }
+
+.new-error-logs-promo {
+  display: flex;
+  gap: var(--spacing-04);
+  font-weight: bold;
+  font-size: var(--font-size-02);
+  line-height: var(--line-height-02);
+  background-color: black;
+  border-radius: var(--border-radius-base);
+}

+ 1 - 0
services/web/locales/en.json

@@ -697,6 +697,7 @@
   "error": "Error",
   "error_assist": "Error Assist",
   "error_log": "Error log",
+  "error_logs_have_had_an_update": "Error logs have had an update",
   "error_opening_document": "Error opening document",
   "error_opening_document_detail": "Sorry, something went wrong opening this document. Please try again.",
   "error_performing_request": "An error has occurred while performing your request.",