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

Merge pull request #12417 from overleaf/ii-history-react-toggle-switch

[web] Toggle switch history migration

GitOrigin-RevId: c0812d03d576bc66dd8878fa80d4ac18dd8576d0
ilkin-overleaf 3 лет назад
Родитель
Сommit
867b37b76f

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

@@ -347,6 +347,9 @@
   "hide_document_preamble": "",
   "hide_outline": "",
   "history": "",
+  "history_view_a11y_description": "",
+  "history_view_all": "",
+  "history_view_labels": "",
   "hotkey_add_a_comment": "",
   "hotkey_autocomplete_menu": "",
   "hotkey_beginning_of_document": "",

+ 10 - 4
services/web/frontend/js/features/history/components/change-list/change-list.tsx

@@ -1,15 +1,21 @@
+import usePersistedState from '../../../../shared/hooks/use-persisted-state'
 import ToggleSwitch from './toggle-switch'
 import Main from './main'
-import { useState } from 'react'
+import { useHistoryContext } from '../../context/history-context'
 
 function ChangeList() {
-  // eslint-disable-next-line no-unused-vars
-  const [labelsOnly, setLabelsOnly] = useState(false)
+  const { projectId, isError } = useHistoryContext()
+  const [labelsOnly, setLabelsOnly] = usePersistedState(
+    `history.userPrefs.showOnlyLabels.${projectId}`,
+    false
+  )
 
   return (
     <aside className="change-list">
       <div className="history-header toggle-switch-container">
-        <ToggleSwitch />
+        {!isError && (
+          <ToggleSwitch labelsOnly={labelsOnly} setLabelsOnly={setLabelsOnly} />
+        )}
       </div>
       <div className="version-list-container">
         <Main />

+ 42 - 2
services/web/frontend/js/features/history/components/change-list/toggle-switch.tsx

@@ -1,5 +1,45 @@
-function ToggleSwitch() {
-  return <div>Toggle Switch</div>
+import { useTranslation } from 'react-i18next'
+
+type ToggleSwitchProps = {
+  labelsOnly: boolean
+  setLabelsOnly: React.Dispatch<
+    React.SetStateAction<ToggleSwitchProps['labelsOnly']>
+  >
+}
+
+function ToggleSwitch({ labelsOnly, setLabelsOnly }: ToggleSwitchProps) {
+  const { t } = useTranslation()
+
+  return (
+    <fieldset className="toggle-switch">
+      <legend className="sr-only">{t('history_view_a11y_description')}</legend>
+      <input
+        type="radio"
+        name="labels-only-toggle-switch"
+        checked={!labelsOnly}
+        onChange={() => setLabelsOnly(false)}
+        className="toggle-switch-input"
+        id="toggle-switch-all-history"
+      />
+      <label
+        htmlFor="toggle-switch-all-history"
+        className="toggle-switch-label"
+      >
+        <span>{t('history_view_all')}</span>
+      </label>
+      <input
+        type="radio"
+        name="labels-only-toggle-switch"
+        checked={labelsOnly}
+        onChange={() => setLabelsOnly(true)}
+        className="toggle-switch-input"
+        id="toggle-switch-labels"
+      />
+      <label htmlFor="toggle-switch-labels" className="toggle-switch-label">
+        <span>{t('history_view_labels')}</span>
+      </label>
+    </fieldset>
+  )
 }
 
 export default ToggleSwitch

+ 6 - 12
services/web/frontend/js/features/history/context/history-context.tsx

@@ -20,8 +20,6 @@ function useHistory() {
   const [nextBeforeTimestamp, setNextBeforeTimestamp] =
     useState<HistoryContextValue['nextBeforeTimestamp']>(null)
   const [atEnd, setAtEnd] = useState<HistoryContextValue['atEnd']>(false)
-  const [showOnlyLabels, setShowOnlyLabels] =
-    useState<HistoryContextValue['showOnlyLabels']>(false)
   const [userHasFullFeature, setUserHasFullFeature] =
     useState<HistoryContextValue['userHasFullFeature']>(undefined)
   const [freeHistoryLimitHit, setFreeHistoryLimitHit] =
@@ -44,12 +42,8 @@ function useHistory() {
   })
   /* eslint-enable no-unused-vars */
 
-  const {
-    isLoading: loading,
-    error,
-    data,
-    runAsync,
-  } = useAsync<{ updates: Update[] }>()
+  const { isLoading, isError, error, data, runAsync } =
+    useAsync<{ updates: Update[] }>()
   const updates = useMemo(() => data?.updates ?? [], [data?.updates])
   const loadingFileTree = true
 
@@ -92,13 +86,13 @@ function useHistory() {
     () => ({
       atEnd,
       error,
+      isError,
+      isLoading,
       freeHistoryLimitHit,
-      loading,
       labels,
       loadingFileTree,
       nextBeforeTimestamp,
       selection,
-      showOnlyLabels,
       updates,
       userHasFullFeature,
       viewMode,
@@ -111,13 +105,13 @@ function useHistory() {
     [
       atEnd,
       error,
+      isError,
+      isLoading,
       freeHistoryLimitHit,
-      loading,
       labels,
       loadingFileTree,
       nextBeforeTimestamp,
       selection,
-      showOnlyLabels,
       updates,
       userHasFullFeature,
       viewMode,

+ 2 - 2
services/web/frontend/js/features/history/context/types/history-context-value.ts

@@ -7,13 +7,13 @@ export type HistoryContextValue = {
   updates: Update[]
   viewMode: string
   nextBeforeTimestamp: Nullable<number>
-  loading: boolean
   atEnd: boolean
   userHasFullFeature: boolean | undefined
   freeHistoryLimitHit: boolean
   selection: Selection
+  isError: boolean
+  isLoading: boolean
   error: Nullable<unknown>
-  showOnlyLabels: boolean
   labels: Nullable<unknown>
   loadingFileTree: boolean
   projectId: string

+ 41 - 0
services/web/frontend/stories/history/toggle-switch.stories.tsx

@@ -0,0 +1,41 @@
+import { useState } from 'react'
+import ToggleSwitchComponent from '../../js/features/history/components/change-list/toggle-switch'
+
+export const LabelsOnlyToggleSwitch = () => {
+  const [labelsOnly, setLabelsOnly] = useState(false)
+
+  return (
+    <ToggleSwitchComponent
+      labelsOnly={labelsOnly}
+      setLabelsOnly={setLabelsOnly}
+    />
+  )
+}
+
+export default {
+  title: 'History / Change list',
+  component: ToggleSwitchComponent,
+  argTypes: {
+    labelsOnly: {
+      table: {
+        disable: true,
+      },
+    },
+    setLabelsOnly: {
+      table: {
+        disable: true,
+      },
+    },
+  },
+  decorators: [
+    (Story: React.ComponentType) => (
+      <div className="history-react">
+        <div className="change-list">
+          <div className="history-header toggle-switch-container">
+            <Story />
+          </div>
+        </div>
+      </div>
+    ),
+  ],
+}

+ 8 - 0
services/web/frontend/stylesheets/app/editor/history-react.less

@@ -46,4 +46,12 @@ history-root {
       padding: 0 16px;
     }
   }
+
+  .toggle-switch-label {
+    flex: 1;
+
+    span {
+      display: block;
+    }
+  }
 }

+ 35 - 0
services/web/test/frontend/features/history/components/chnage-list.spec.tsx

@@ -0,0 +1,35 @@
+import { useState } from 'react'
+import ToggleSwitch from '../../../../../frontend/js/features/history/components/change-list/toggle-switch'
+
+describe('change list', function () {
+  describe('toggle switch', function () {
+    it('renders switch buttons', function () {
+      cy.mount(<ToggleSwitch labelsOnly={false} setLabelsOnly={() => {}} />)
+
+      cy.findByLabelText(/all history/i)
+      cy.findByLabelText(/labels/i)
+    })
+
+    it('toggles "all history" and "labels" buttons', function () {
+      function ToggleSwitchWrapped({ labelsOnly }: { labelsOnly: boolean }) {
+        const [labelsOnlyLocal, setLabelsOnlyLocal] = useState(labelsOnly)
+        return (
+          <ToggleSwitch
+            labelsOnly={labelsOnlyLocal}
+            setLabelsOnly={setLabelsOnlyLocal}
+          />
+        )
+      }
+
+      cy.mount(<ToggleSwitchWrapped labelsOnly={false} />)
+
+      cy.findByLabelText(/all history/i).as('all-history')
+      cy.findByLabelText(/labels/i).as('labels')
+      cy.get('@all-history').should('be.checked')
+      cy.get('@labels').should('not.be.checked')
+      cy.get('@labels').click({ force: true })
+      cy.get('@all-history').should('not.be.checked')
+      cy.get('@labels').should('be.checked')
+    })
+  })
+})