Преглед изворни кода

Merge pull request #25398 from overleaf/dp-file-tree-proptypes

Remove PropTypes from file-tree components

GitOrigin-RevId: 7ecbf9778da59b852be8678c5dff61e13d927b9c
David пре 1 година
родитељ
комит
8e31c30ec7

+ 0 - 9
services/web/frontend/js/features/file-tree/components/file-tree-create/danger-message.jsx

@@ -1,9 +0,0 @@
-import OLNotification from '@/features/ui/components/ol/ol-notification'
-import PropTypes from 'prop-types'
-
-export default function DangerMessage({ children }) {
-  return <OLNotification type="error" content={children} />
-}
-DangerMessage.propTypes = {
-  children: PropTypes.any.isRequired,
-}

+ 9 - 0
services/web/frontend/js/features/file-tree/components/file-tree-create/danger-message.tsx

@@ -0,0 +1,9 @@
+import OLNotification from '@/features/ui/components/ol/ol-notification'
+
+export default function DangerMessage({
+  children,
+}: {
+  children: React.ReactNode
+}) {
+  return <OLNotification type="error" content={children} />
+}

+ 6 - 5
services/web/frontend/js/features/file-tree/components/file-tree-create/error-message.jsx → services/web/frontend/js/features/file-tree/components/file-tree-create/error-message.tsx

@@ -1,4 +1,3 @@
-import PropTypes from 'prop-types'
 import { useTranslation } from 'react-i18next'
 import { FetchError } from '../../../../infrastructure/fetch-json'
 import RedirectToLogin from './redirect-to-login'
@@ -9,7 +8,12 @@ import {
 } from '../../errors'
 import DangerMessage from './danger-message'
 
-export default function ErrorMessage({ error }) {
+// TODO: Update the error type when we properly type FileTreeActionableContext
+export default function ErrorMessage({
+  error,
+}: {
+  error: string | Record<string, any>
+}) {
   const { t } = useTranslation()
   const fileNameLimit = 150
 
@@ -119,6 +123,3 @@ export default function ErrorMessage({ error }) {
       return <DangerMessage>{t('generic_something_went_wrong')}</DangerMessage>
   }
 }
-ErrorMessage.propTypes = {
-  error: PropTypes.oneOfType([PropTypes.string, PropTypes.object]).isRequired,
-}

+ 11 - 17
services/web/frontend/js/features/file-tree/components/file-tree-create/file-tree-create-name-input.jsx → services/web/frontend/js/features/file-tree/components/file-tree-create/file-tree-create-name-input.tsx

@@ -1,7 +1,6 @@
 import { useRef, useEffect } from 'react'
 import { useTranslation } from 'react-i18next'
 import { useFileTreeCreateName } from '../../contexts/file-tree-create-name'
-import PropTypes from 'prop-types'
 import {
   BlockedFilenameError,
   DuplicateFilenameError,
@@ -23,6 +22,15 @@ export default function FileTreeCreateNameInput({
   placeholder,
   error,
   inFlight,
+}: {
+  label?: string
+  focusName?: boolean
+  classes?: {
+    formGroup?: string
+  }
+  placeholder?: string
+  error?: string | Record<string, any>
+  inFlight: boolean
 }) {
   const { t } = useTranslation()
 
@@ -30,7 +38,7 @@ export default function FileTreeCreateNameInput({
   const { name, setName, touchedName, validName } = useFileTreeCreateName()
 
   // focus the first part of the filename if needed
-  const inputRef = useRef(null)
+  const inputRef = useRef<HTMLInputElement>(null)
 
   useEffect(() => {
     if (inputRef.current && focusName) {
@@ -73,18 +81,7 @@ export default function FileTreeCreateNameInput({
   )
 }
 
-FileTreeCreateNameInput.propTypes = {
-  focusName: PropTypes.bool,
-  label: PropTypes.string,
-  classes: PropTypes.shape({
-    formGroup: PropTypes.string,
-  }),
-  placeholder: PropTypes.string,
-  error: PropTypes.oneOfType([PropTypes.object, PropTypes.string]),
-  inFlight: PropTypes.bool.isRequired,
-}
-
-function ErrorMessage({ error }) {
+function ErrorMessage({ error }: { error: string | Record<string, any> }) {
   const { t } = useTranslation()
 
   // if (typeof error === 'string') {
@@ -124,6 +121,3 @@ function ErrorMessage({ error }) {
       return null // other errors are displayed elsewhere
   }
 }
-ErrorMessage.propTypes = {
-  error: PropTypes.oneOfType([PropTypes.object, PropTypes.string]).isRequired,
-}

+ 15 - 15
services/web/frontend/js/features/file-tree/components/file-tree-create/file-tree-modal-create-file-footer.jsx → services/web/frontend/js/features/file-tree/components/file-tree-create/file-tree-modal-create-file-footer.tsx

@@ -2,7 +2,6 @@ import { useTranslation } from 'react-i18next'
 import { useFileTreeCreateForm } from '../../contexts/file-tree-create-form'
 import { useFileTreeActionable } from '../../contexts/file-tree-actionable'
 import { useFileTreeData } from '../../../../shared/context/file-tree-data-context'
-import PropTypes from 'prop-types'
 import OLButton from '@/features/ui/components/ol/ol-button'
 import OLNotification from '@/features/ui/components/ol/ol-notification'
 
@@ -26,21 +25,33 @@ export function FileTreeModalCreateFileFooterContent({
   valid,
   fileCount,
   inFlight,
-  newFileCreateMode,
   cancel,
+  newFileCreateMode,
+}: {
+  valid: boolean
+  fileCount:
+    | {
+        limit: number
+        status: string
+        value: number
+      }
+    | number
+  inFlight: boolean
+  cancel: () => void
+  newFileCreateMode?: string
 }) {
   const { t } = useTranslation()
 
   return (
     <>
-      {fileCount.status === 'warning' && (
+      {typeof fileCount !== 'number' && fileCount.status === 'warning' && (
         <div className="modal-footer-left approaching-file-limit">
           {t('project_approaching_file_limit')} ({fileCount.value}/
           {fileCount.limit})
         </div>
       )}
 
-      {fileCount.status === 'error' && (
+      {typeof fileCount !== 'number' && fileCount.status === 'error' && (
         <OLNotification
           type="error"
           className="at-file-limit"
@@ -73,14 +84,3 @@ export function FileTreeModalCreateFileFooterContent({
     </>
   )
 }
-FileTreeModalCreateFileFooterContent.propTypes = {
-  cancel: PropTypes.func.isRequired,
-  fileCount: PropTypes.shape({
-    limit: PropTypes.number.isRequired,
-    status: PropTypes.string.isRequired,
-    value: PropTypes.number.isRequired,
-  }).isRequired,
-  inFlight: PropTypes.bool.isRequired,
-  newFileCreateMode: PropTypes.string,
-  valid: PropTypes.bool.isRequired,
-}

+ 9 - 8
services/web/frontend/js/features/file-tree/components/file-tree-create/file-tree-modal-create-file-mode.jsx → services/web/frontend/js/features/file-tree/components/file-tree-create/file-tree-modal-create-file-mode.tsx

@@ -1,11 +1,18 @@
 import classnames from 'classnames'
-import PropTypes from 'prop-types'
 import { useFileTreeActionable } from '../../contexts/file-tree-actionable'
 import * as eventTracking from '../../../../infrastructure/event-tracking'
 import OLButton from '@/features/ui/components/ol/ol-button'
 import MaterialIcon from '@/shared/components/material-icon'
 
-export default function FileTreeModalCreateFileMode({ mode, icon, label }) {
+export default function FileTreeModalCreateFileMode({
+  mode,
+  icon,
+  label,
+}: {
+  mode: string
+  icon: string
+  label: string
+}) {
   const { newFileCreateMode, startCreatingFile } = useFileTreeActionable()
 
   const handleClick = () => {
@@ -27,9 +34,3 @@ export default function FileTreeModalCreateFileMode({ mode, icon, label }) {
     </li>
   )
 }
-
-FileTreeModalCreateFileMode.propTypes = {
-  mode: PropTypes.string.isRequired,
-  icon: PropTypes.string.isRequired,
-  label: PropTypes.string.isRequired,
-}

+ 12 - 20
services/web/frontend/js/features/file-tree/components/file-tree-draggable-preview-layer.jsx → services/web/frontend/js/features/file-tree/components/file-tree-draggable-preview-layer.tsx

@@ -1,6 +1,6 @@
 import { useRef } from 'react'
-import PropTypes from 'prop-types'
 import classNames from 'classnames'
+import { XYCoord } from 'react-dnd'
 
 // a custom component rendered on top of a draggable area that renders the
 // dragged item. See
@@ -12,8 +12,13 @@ function FileTreeDraggablePreviewLayer({
   isDragging,
   item,
   clientOffset,
+}: {
+  isOver: boolean
+  isDragging: boolean
+  item: { title: string }
+  clientOffset: XYCoord | null
 }) {
-  const ref = useRef()
+  const ref = useRef<HTMLDivElement>(null)
 
   return (
     <div
@@ -36,29 +41,16 @@ function FileTreeDraggablePreviewLayer({
   )
 }
 
-FileTreeDraggablePreviewLayer.propTypes = {
-  isOver: PropTypes.bool.isRequired,
-  isDragging: PropTypes.bool.isRequired,
-  item: PropTypes.shape({
-    title: PropTypes.string,
-  }),
-  clientOffset: PropTypes.shape({
-    x: PropTypes.number,
-    y: PropTypes.number,
-  }),
-}
-
-function DraggablePreviewItem({ title }) {
+function DraggablePreviewItem({ title }: { title: string }) {
   return <div className="dnd-draggable-preview-item">{title}</div>
 }
 
-DraggablePreviewItem.propTypes = {
-  title: PropTypes.string.isRequired,
-}
-
 // makes the preview item follow the cursor.
 // See https://react-dnd.github.io/react-dnd/docs/api/drag-layer-monitor
-function getItemStyle(clientOffset, containerOffset) {
+function getItemStyle(
+  clientOffset: XYCoord | null,
+  containerOffset: DOMRect | undefined
+) {
   if (!containerOffset || !clientOffset) {
     return {
       display: 'none',

+ 11 - 14
services/web/frontend/js/features/file-tree/components/modals/file-tree-modal-create-folder.jsx → services/web/frontend/js/features/file-tree/components/modals/file-tree-modal-create-folder.tsx

@@ -1,5 +1,4 @@
-import { useEffect, useState } from 'react'
-import PropTypes from 'prop-types'
+import React, { useEffect, useState } from 'react'
 import { useTranslation } from 'react-i18next'
 import { useRefWithAutoFocus } from '../../../../shared/hooks/use-ref-with-auto-focus'
 import { useFileTreeActionable } from '../../contexts/file-tree-actionable'
@@ -109,19 +108,25 @@ function InputName({
   validName,
   setValidName,
   handleCreateFolder,
+}: {
+  name: string
+  setName: (name: string) => void
+  validName: boolean
+  setValidName: (validName: boolean) => void
+  handleCreateFolder: () => void
 }) {
-  const { autoFocusedRef } = useRefWithAutoFocus()
+  const { autoFocusedRef } = useRefWithAutoFocus<HTMLInputElement>()
 
-  function handleFocus(ev) {
+  function handleFocus(ev: React.FocusEvent<HTMLInputElement>) {
     ev.target.setSelectionRange(0, -1)
   }
 
-  function handleChange(ev) {
+  function handleChange(ev: React.ChangeEvent<HTMLInputElement>) {
     setValidName(isCleanFilename(ev.target.value.trim()))
     setName(ev.target.value)
   }
 
-  function handleKeyDown(ev) {
+  function handleKeyDown(ev: React.KeyboardEvent<HTMLInputElement>) {
     if (ev.key === 'Enter' && validName) {
       handleCreateFolder()
     }
@@ -140,12 +145,4 @@ function InputName({
   )
 }
 
-InputName.propTypes = {
-  name: PropTypes.string.isRequired,
-  setName: PropTypes.func.isRequired,
-  validName: PropTypes.bool.isRequired,
-  setValidName: PropTypes.func.isRequired,
-  handleCreateFolder: PropTypes.func.isRequired,
-}
-
 export default FileTreeModalCreateFolder