Merge pull request #14999 from overleaf/mf-file-view-header-typescript

[web] Convert `file-view-header.js` to typescript

GitOrigin-RevId: 1f05b086e3acb692f3745481c4022a920c4f7599
This commit is contained in:
M Fahru 2023-09-27 10:01:30 -07:00 committed by Copybot
parent bfac201236
commit 496bb4d4e7
4 changed files with 82 additions and 38 deletions

View file

@ -1,4 +1,4 @@
import { useState, useCallback } from 'react'
import { useState, useCallback, type ElementType } from 'react'
import PropTypes from 'prop-types'
import { Trans, useTranslation } from 'react-i18next'
@ -11,18 +11,27 @@ import { useProjectContext } from '../../../shared/context/project-context'
import importOverleafModules from '../../../../macros/import-overleaf-module.macro'
import useAbortController from '../../../shared/hooks/use-abort-controller'
import { LinkedFileIcon } from './file-view-icons'
import { BinaryFile, hasProvider, LinkedFile } from '../types/binary-file'
import { debugConsole } from '@/utils/debugging'
const tprLinkedFileInfo = importOverleafModules('tprLinkedFileInfo')
const tprLinkedFileInfo = importOverleafModules('tprLinkedFileInfo') as {
import: { LinkedFileInfo: ElementType }
path: string
}[]
const tprLinkedFileRefreshError = importOverleafModules(
'tprLinkedFileRefreshError'
)
) as {
import: { LinkedFileRefreshError: ElementType }
path: string
}[]
const MAX_URL_LENGTH = 60
const FRONT_OF_URL_LENGTH = 35
const FILLER = '...'
const TAIL_OF_URL_LENGTH = MAX_URL_LENGTH - FRONT_OF_URL_LENGTH - FILLER.length
function shortenedUrl(url) {
function shortenedUrl(url: string) {
if (!url) {
return
}
@ -34,7 +43,15 @@ function shortenedUrl(url) {
return url
}
export default function FileViewHeader({ file, storeReferencesKeys }) {
type FileViewHeaderProps = {
file: BinaryFile
storeReferencesKeys: (keys: string[]) => void
}
export default function FileViewHeader({
file,
storeReferencesKeys,
}: FileViewHeaderProps) {
const { _id: projectId } = useProjectContext({
_id: PropTypes.string.isRequired,
})
@ -50,19 +67,19 @@ export default function FileViewHeader({ file, storeReferencesKeys }) {
let fileInfo
if (file.linkedFileData) {
if (file.linkedFileData.provider === 'url') {
if (hasProvider(file, 'url')) {
fileInfo = (
<div>
<UrlProvider file={file} />
</div>
)
} else if (file.linkedFileData.provider === 'project_file') {
} else if (hasProvider(file, 'project_file')) {
fileInfo = (
<div>
<ProjectFilePathProvider file={file} />
</div>
)
} else if (file.linkedFileData.provider === 'project_output_file') {
} else if (hasProvider(file, 'project_output_file')) {
fileInfo = (
<div>
<ProjectOutputFileProvider file={file} />
@ -85,8 +102,8 @@ export default function FileViewHeader({ file, storeReferencesKeys }) {
})
.finally(() => {
if (
file.linkedFileData.provider === 'mendeley' ||
file.linkedFileData.provider === 'zotero' ||
hasProvider(file, 'mendeley') ||
hasProvider(file, 'zotero') ||
file.name.match(/^.*\.bib$/)
) {
reindexReferences()
@ -151,16 +168,11 @@ export default function FileViewHeader({ file, storeReferencesKeys }) {
)
}
FileViewHeader.propTypes = {
file: PropTypes.shape({
id: PropTypes.string,
name: PropTypes.string,
linkedFileData: PropTypes.object,
}).isRequired,
storeReferencesKeys: PropTypes.func.isRequired,
type UrlProviderProps = {
file: LinkedFile<'url'>
}
function UrlProvider({ file }) {
function UrlProvider({ file }: UrlProviderProps) {
return (
<p>
<LinkedFileIcon />
@ -181,14 +193,11 @@ function UrlProvider({ file }) {
)
}
UrlProvider.propTypes = {
file: PropTypes.shape({
linkedFileData: PropTypes.object,
created: PropTypes.string,
}).isRequired,
type ProjectFilePathProviderProps = {
file: LinkedFile<'project_file'>
}
function ProjectFilePathProvider({ file }) {
function ProjectFilePathProvider({ file }: ProjectFilePathProviderProps) {
/* eslint-disable jsx-a11y/anchor-has-content, react/jsx-key */
return (
<p>
@ -218,14 +227,11 @@ function ProjectFilePathProvider({ file }) {
)
}
ProjectFilePathProvider.propTypes = {
file: PropTypes.shape({
linkedFileData: PropTypes.object,
created: PropTypes.string,
}).isRequired,
type ProjectOutputFileProviderProps = {
file: LinkedFile<'project_output_file'>
}
function ProjectOutputFileProvider({ file }) {
function ProjectOutputFileProvider({ file }: ProjectOutputFileProviderProps) {
return (
<p>
<LinkedFileIcon />
@ -252,10 +258,3 @@ function ProjectOutputFileProvider({ file }) {
</p>
)
}
ProjectOutputFileProvider.propTypes = {
file: PropTypes.shape({
linkedFileData: PropTypes.object,
created: PropTypes.string,
}).isRequired,
}

View file

@ -0,0 +1,44 @@
type LinkedFileData = {
url: {
provider: 'url'
url: string
}
zotero: {
provider: 'zotero'
importer_id: string
}
mendeley: {
provider: 'mendeley'
importer_id: string
}
project_file: {
provider: 'project_file'
v1_source_doc_id?: string
source_project_id: string
source_entity_path: string
}
project_output_file: {
provider: 'project_output_file'
v1_source_doc_id?: string
source_project_id: string
source_output_file_path: string
}
}
export type BinaryFile<T extends keyof LinkedFileData = keyof LinkedFileData> =
{
_id: string
name: string
created: Date
id: string
type: string
selected: boolean
linkedFileData?: LinkedFileData[T]
}
export type LinkedFile<T extends keyof LinkedFileData> = Required<BinaryFile<T>>
export const hasProvider = <T extends keyof LinkedFileData>(
file: BinaryFile,
provider: T
): file is LinkedFile<T> => file.linkedFileData?.provider === provider

View file

@ -8,7 +8,7 @@ import fetchMock from 'fetch-mock'
import sinon from 'sinon'
import { renderWithEditorContext } from '../../../helpers/render-with-context'
import FileViewHeader from '../../../../../frontend/js/features/file-view/components/file-view-header.js'
import FileViewHeader from '../../../../../frontend/js/features/file-view/components/file-view-header'
describe('<FileViewHeader/>', function () {
const urlFile = {

View file

@ -39,5 +39,6 @@ declare global {
enterprise?: boolean
useRecaptchaNet?: boolean
}
expectingLinkedFileRefreshedSocketFor?: string | null
}
}