mirror of
https://github.com/overleaf/overleaf.git
synced 2024-11-21 20:47:08 -05:00
[web] Migrate the file view to Bootstrap 5 (#20765)
* [web] Remove unnecessary divs around `fileInfo` * [web] Add file-view SCSS style * [web] Simplify `TPRFileViewInfo` * [web] Add div for action buttons * [web] Misc. simplifications * [web] Add Overleaf logo in bg when selecting multiple files * [web] Add message when multiple files are selected * [web] Add .full-size class * [web] Import styles from LESS file * [web] Update icons, use MaterialIcon * [web] Use OLButton * [web] Add missing space between icons and text * [web] Adjust margins * [web] Fix alert button * [web] Update Alerts * [web] Update `FileViewLoadingIndicator` * [web] Fix test "shows a loading indicator..." This was failing because `LoadingSpinner` is shown after a setTimeout. Maybe we can skip this setTimeout when delay==0 ? * [web] Remove Row/Col around error notifications * [web] Replace `!!` by `Boolean` Co-authored-by: ilkin-overleaf <100852799+ilkin-overleaf@users.noreply.github.com> * [web] Use `alert` class in BS3 only Co-authored-by: Ilkin Ismailov <ilkin.ismailov@overleaf.com> * [web] Update "Go to settings" to OLButton Co-authored-by: Ilkin Ismailov <ilkin.ismailov@overleaf.com> * [web] Use `BootstrapVersionSwitcher` instead of `isBootstrap5` Co-authored-by: Ilkin Ismailov <ilkin.ismailov@overleaf.com> * [web] Align Alert content to the left in BS5 * [web] Remove `leadingIcon` on Refresh buttons * [web] Make the download link be an OLButton * [web] Set `tpr-refresh-error` in BS3 only Co-authored-by: Rebeka Dekany <50901361+rebekadekany@users.noreply.github.com> * [web] Use `var(--white);` instead of `white` Co-authored-by: Rebeka <rebeka.dekany@overleaf.com> * [web] Update OLButton size (small -> sm) --------- Co-authored-by: ilkin-overleaf <100852799+ilkin-overleaf@users.noreply.github.com> Co-authored-by: Ilkin Ismailov <ilkin.ismailov@overleaf.com> Co-authored-by: Rebeka Dekany <50901361+rebekadekany@users.noreply.github.com> Co-authored-by: Rebeka <rebeka.dekany@overleaf.com> GitOrigin-RevId: 04f369c0f1a53d47619a1570648ee58de5050751
This commit is contained in:
parent
2e080a3a34
commit
d6de6da781
11 changed files with 223 additions and 74 deletions
|
@ -4,7 +4,7 @@ import { Trans, useTranslation } from 'react-i18next'
|
||||||
import Icon from '../../../shared/components/icon'
|
import Icon from '../../../shared/components/icon'
|
||||||
import { formatTime, relativeDate } from '../../utils/format-date'
|
import { formatTime, relativeDate } from '../../utils/format-date'
|
||||||
import { useFileTreeData } from '@/shared/context/file-tree-data-context'
|
import { useFileTreeData } from '@/shared/context/file-tree-data-context'
|
||||||
import { useProjectContext } from '../../../shared/context/project-context'
|
import { useProjectContext } from '@/shared/context/project-context'
|
||||||
|
|
||||||
import { Nullable } from '../../../../../types/utils'
|
import { Nullable } from '../../../../../types/utils'
|
||||||
import importOverleafModules from '../../../../macros/import-overleaf-module.macro'
|
import importOverleafModules from '../../../../macros/import-overleaf-module.macro'
|
||||||
|
@ -13,6 +13,9 @@ import { BinaryFile, hasProvider, LinkedFile } from '../types/binary-file'
|
||||||
import FileViewRefreshButton from './file-view-refresh-button'
|
import FileViewRefreshButton from './file-view-refresh-button'
|
||||||
import FileViewRefreshError from './file-view-refresh-error'
|
import FileViewRefreshError from './file-view-refresh-error'
|
||||||
import { useSnapshotContext } from '@/features/ide-react/context/snapshot-context'
|
import { useSnapshotContext } from '@/features/ide-react/context/snapshot-context'
|
||||||
|
import MaterialIcon from '@/shared/components/material-icon'
|
||||||
|
import BootstrapVersionSwitcher from '@/features/ui/components/bootstrap-5/bootstrap-version-switcher'
|
||||||
|
import OLButton from '@/features/ui/components/ol/ol-button'
|
||||||
|
|
||||||
const tprFileViewInfo = importOverleafModules('tprFileViewInfo') as {
|
const tprFileViewInfo = importOverleafModules('tprFileViewInfo') as {
|
||||||
import: { TPRFileViewInfo: ElementType }
|
import: { TPRFileViewInfo: ElementType }
|
||||||
|
@ -58,50 +61,44 @@ export default function FileViewHeader({ file }: FileViewHeaderProps) {
|
||||||
let fileInfo
|
let fileInfo
|
||||||
if (file.linkedFileData) {
|
if (file.linkedFileData) {
|
||||||
if (hasProvider(file, 'url')) {
|
if (hasProvider(file, 'url')) {
|
||||||
fileInfo = (
|
fileInfo = <UrlProvider file={file} />
|
||||||
<div>
|
|
||||||
<UrlProvider file={file} />
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
} else if (hasProvider(file, 'project_file')) {
|
} else if (hasProvider(file, 'project_file')) {
|
||||||
fileInfo = (
|
fileInfo = <ProjectFilePathProvider file={file} />
|
||||||
<div>
|
|
||||||
<ProjectFilePathProvider file={file} />
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
} else if (hasProvider(file, 'project_output_file')) {
|
} else if (hasProvider(file, 'project_output_file')) {
|
||||||
fileInfo = (
|
fileInfo = <ProjectOutputFileProvider file={file} />
|
||||||
<div>
|
|
||||||
<ProjectOutputFileProvider file={file} />
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<>
|
||||||
{file.linkedFileData && fileInfo}
|
{file.linkedFileData && fileInfo}
|
||||||
{file.linkedFileData &&
|
{file.linkedFileData &&
|
||||||
tprFileViewInfo.map(({ import: { TPRFileViewInfo }, path }) => (
|
tprFileViewInfo.map(({ import: { TPRFileViewInfo }, path }) => (
|
||||||
<TPRFileViewInfo key={path} file={file} />
|
<TPRFileViewInfo key={path} file={file} />
|
||||||
))}
|
))}
|
||||||
|
<div className="file-view-buttons">
|
||||||
{file.linkedFileData && !fileTreeReadOnly && (
|
{file.linkedFileData && !fileTreeReadOnly && (
|
||||||
<FileViewRefreshButton file={file} setRefreshError={setRefreshError} />
|
<FileViewRefreshButton
|
||||||
|
file={file}
|
||||||
|
setRefreshError={setRefreshError}
|
||||||
|
/>
|
||||||
)}
|
)}
|
||||||
|
<OLButton
|
||||||
<a
|
variant="secondary"
|
||||||
download={file.name}
|
download={file.name}
|
||||||
href={
|
href={
|
||||||
fileTreeFromHistory
|
fileTreeFromHistory
|
||||||
? `/project/${projectId}/blob/${file.hash}`
|
? `/project/${projectId}/blob/${file.hash}`
|
||||||
: `/project/${projectId}/file/${file.id}`
|
: `/project/${projectId}/file/${file.id}`
|
||||||
}
|
}
|
||||||
className="btn btn-secondary-info btn-secondary"
|
|
||||||
>
|
>
|
||||||
<Icon type="download" fw />
|
<BootstrapVersionSwitcher
|
||||||
|
bs3={<Icon type="download" fw />}
|
||||||
|
bs5={<MaterialIcon type="download" className="align-middle" />}
|
||||||
|
/>{' '}
|
||||||
<span>{t('download')}</span>
|
<span>{t('download')}</span>
|
||||||
</a>
|
</OLButton>
|
||||||
|
</div>
|
||||||
{file.linkedFileData &&
|
{file.linkedFileData &&
|
||||||
tprFileViewNotOriginalImporter.map(
|
tprFileViewNotOriginalImporter.map(
|
||||||
({ import: { TPRFileViewNotOriginalImporter }, path }) => (
|
({ import: { TPRFileViewNotOriginalImporter }, path }) => (
|
||||||
|
@ -111,7 +108,7 @@ export default function FileViewHeader({ file }: FileViewHeaderProps) {
|
||||||
{refreshError && (
|
{refreshError && (
|
||||||
<FileViewRefreshError file={file} refreshError={refreshError} />
|
<FileViewRefreshError file={file} refreshError={refreshError} />
|
||||||
)}
|
)}
|
||||||
</div>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -150,7 +147,7 @@ function ProjectFilePathProvider({ file }: ProjectFilePathProviderProps) {
|
||||||
/* eslint-disable jsx-a11y/anchor-has-content, react/jsx-key */
|
/* eslint-disable jsx-a11y/anchor-has-content, react/jsx-key */
|
||||||
return (
|
return (
|
||||||
<p>
|
<p>
|
||||||
<LinkedFileIcon />
|
<LinkedFileIcon />{' '}
|
||||||
<Trans
|
<Trans
|
||||||
i18nKey="imported_from_another_project_at_date"
|
i18nKey="imported_from_another_project_at_date"
|
||||||
components={
|
components={
|
||||||
|
|
|
@ -1,12 +1,26 @@
|
||||||
import Icon from '../../../shared/components/icon'
|
import Icon from '../../../shared/components/icon'
|
||||||
|
import MaterialIcon from '@/shared/components/material-icon'
|
||||||
|
import BootstrapVersionSwitcher from '@/features/ui/components/bootstrap-5/bootstrap-version-switcher'
|
||||||
|
|
||||||
export const LinkedFileIcon = props => {
|
export const LinkedFileIcon = props => {
|
||||||
return (
|
return (
|
||||||
|
<BootstrapVersionSwitcher
|
||||||
|
bs3={
|
||||||
<Icon
|
<Icon
|
||||||
type="external-link-square"
|
type="external-link-square"
|
||||||
modifier="rotate-180"
|
modifier="rotate-180"
|
||||||
className="linked-file-icon"
|
className="linked-file-icon"
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
|
}
|
||||||
|
bs5={
|
||||||
|
<MaterialIcon
|
||||||
|
type="open_in_new"
|
||||||
|
modifier="rotate-180"
|
||||||
|
className="align-middle linked-file-icon"
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
/>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,6 +13,7 @@ import useAbortController from '@/shared/hooks/use-abort-controller'
|
||||||
import type { BinaryFile } from '../types/binary-file'
|
import type { BinaryFile } from '../types/binary-file'
|
||||||
import { Nullable } from '../../../../../types/utils'
|
import { Nullable } from '../../../../../types/utils'
|
||||||
import importOverleafModules from '../../../../macros/import-overleaf-module.macro'
|
import importOverleafModules from '../../../../macros/import-overleaf-module.macro'
|
||||||
|
import OLButton from '@/features/ui/components/ol/ol-button'
|
||||||
|
|
||||||
type FileViewRefreshButtonProps = {
|
type FileViewRefreshButtonProps = {
|
||||||
setRefreshError: Dispatch<SetStateAction<Nullable<string>>>
|
setRefreshError: Dispatch<SetStateAction<Nullable<string>>>
|
||||||
|
@ -90,13 +91,21 @@ function FileViewRefreshButtonDefault({
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<button
|
<OLButton
|
||||||
className="btn btn-primary"
|
variant="primary"
|
||||||
onClick={() => refreshFile(null)}
|
onClick={() => refreshFile(null)}
|
||||||
disabled={refreshing}
|
disabled={refreshing}
|
||||||
>
|
isLoading={refreshing}
|
||||||
<Icon type="refresh" spin={refreshing} fw />
|
bs3Props={{
|
||||||
|
loading: (
|
||||||
|
<>
|
||||||
|
<Icon type="refresh" spin={refreshing} fw />{' '}
|
||||||
<span>{refreshing ? `${t('refreshing')}…` : t('refresh')}</span>
|
<span>{refreshing ? `${t('refreshing')}…` : t('refresh')}</span>
|
||||||
</button>
|
</>
|
||||||
|
),
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{t('refresh')}
|
||||||
|
</OLButton>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@ import type { ElementType } from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import importOverleafModules from '../../../../macros/import-overleaf-module.macro'
|
import importOverleafModules from '../../../../macros/import-overleaf-module.macro'
|
||||||
import { BinaryFile } from '../types/binary-file'
|
import { BinaryFile } from '../types/binary-file'
|
||||||
|
import OLNotification from '@/features/ui/components/ol/ol-notification'
|
||||||
|
|
||||||
type FileViewRefreshErrorProps = {
|
type FileViewRefreshErrorProps = {
|
||||||
file: BinaryFile
|
file: BinaryFile
|
||||||
|
@ -33,11 +34,15 @@ export default function FileViewRefreshError({
|
||||||
)[0]
|
)[0]
|
||||||
} else {
|
} else {
|
||||||
return (
|
return (
|
||||||
<div className="row">
|
<div className="file-view-error">
|
||||||
<br />
|
<OLNotification
|
||||||
<div className="alert alert-danger col-md-6 col-md-offset-3">
|
type="error"
|
||||||
|
content={
|
||||||
|
<span>
|
||||||
{t('access_denied')}: {refreshError}
|
{t('access_denied')}: {refreshError}
|
||||||
</div>
|
</span>
|
||||||
|
}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -93,15 +93,13 @@ export default function FileViewText({
|
||||||
fetchDataController,
|
fetchDataController,
|
||||||
])
|
])
|
||||||
return (
|
return (
|
||||||
<div>
|
Boolean(textPreview) && (
|
||||||
{textPreview && (
|
|
||||||
<div className="text-preview">
|
<div className="text-preview">
|
||||||
<div className="scroll-container">
|
<div className="scroll-container">
|
||||||
<p>{textPreview}</p>
|
<p>{textPreview}</p>
|
||||||
{shouldShowDots && <p>...</p>}
|
{shouldShowDots && <p>...</p>}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)
|
||||||
</div>
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,7 @@ import FileViewHeader from './file-view-header'
|
||||||
import FileViewImage from './file-view-image'
|
import FileViewImage from './file-view-image'
|
||||||
import FileViewPdf from './file-view-pdf'
|
import FileViewPdf from './file-view-pdf'
|
||||||
import FileViewText from './file-view-text'
|
import FileViewText from './file-view-text'
|
||||||
import Icon from '../../../shared/components/icon'
|
import LoadingSpinner from '@/shared/components/loading-spinner'
|
||||||
import getMeta from '@/utils/meta'
|
import getMeta from '@/utils/meta'
|
||||||
|
|
||||||
const imageExtensions = ['png', 'jpg', 'jpeg', 'gif']
|
const imageExtensions = ['png', 'jpg', 'jpeg', 'gif']
|
||||||
|
@ -71,13 +71,12 @@ export default function FileView({ file }) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function FileViewLoadingIndicator() {
|
function FileViewLoadingIndicator() {
|
||||||
const { t } = useTranslation()
|
|
||||||
return (
|
return (
|
||||||
<div className="loading-panel loading-panel-file-view">
|
<div
|
||||||
<span>
|
className="loading-panel loading-panel-file-view"
|
||||||
<Icon type="refresh" spin />
|
data-testid="loading-panel-file-view"
|
||||||
{t('loading')}…
|
>
|
||||||
</span>
|
<LoadingSpinner />
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,7 @@ export type ButtonProps = {
|
||||||
children?: ReactNode
|
children?: ReactNode
|
||||||
className?: string
|
className?: string
|
||||||
disabled?: boolean
|
disabled?: boolean
|
||||||
download?: boolean
|
download?: boolean | string
|
||||||
draggable?: boolean
|
draggable?: boolean
|
||||||
form?: string
|
form?: string
|
||||||
leadingIcon?: string | React.ReactNode
|
leadingIcon?: string | React.ReactNode
|
||||||
|
|
|
@ -4,6 +4,33 @@
|
||||||
background-color: @gray-lightest;
|
background-color: @gray-lightest;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
|
|
||||||
|
.file-view-buttons {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: @spacing-03;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.file-view-error {
|
||||||
|
margin: @spacing-08 -15px auto;
|
||||||
|
|
||||||
|
> .alert {
|
||||||
|
max-width: 400px;
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.tpr-refresh-error {
|
||||||
|
.btn {
|
||||||
|
color: @neutral-90;
|
||||||
|
background-color: @white;
|
||||||
|
&:hover {
|
||||||
|
background-color: @neutral-20;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
img,
|
img,
|
||||||
.file-view-pdf {
|
.file-view-pdf {
|
||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
|
@ -43,10 +70,7 @@
|
||||||
line-height: 1.1em;
|
line-height: 1.1em;
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
border: 1px solid @gray-lighter;
|
border: 1px solid @gray-lighter;
|
||||||
padding-left: 12px;
|
padding: 8px 12px;
|
||||||
padding-right: 12px;
|
|
||||||
padding-top: 8px;
|
|
||||||
padding-bottom: 8px;
|
|
||||||
text-align: left;
|
text-align: left;
|
||||||
white-space: pre;
|
white-space: pre;
|
||||||
font-family: monospace;
|
font-family: monospace;
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
@import 'editor/loading-screen';
|
@import 'editor/loading-screen';
|
||||||
@import 'editor/outline';
|
@import 'editor/outline';
|
||||||
@import 'editor/file-tree';
|
@import 'editor/file-tree';
|
||||||
|
@import 'editor/file-view';
|
||||||
@import 'editor/figure-modal';
|
@import 'editor/figure-modal';
|
||||||
@import 'editor/chat';
|
@import 'editor/chat';
|
||||||
@import 'subscription';
|
@import 'subscription';
|
||||||
|
|
|
@ -0,0 +1,102 @@
|
||||||
|
.file-view {
|
||||||
|
padding: var(--spacing-05);
|
||||||
|
text-align: center;
|
||||||
|
overflow: auto;
|
||||||
|
|
||||||
|
.loading-panel {
|
||||||
|
padding-top: 8rem;
|
||||||
|
background: var(--neutral-10);
|
||||||
|
}
|
||||||
|
|
||||||
|
.file-view-buttons {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: var(--spacing-03);
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.file-view-error {
|
||||||
|
margin: var(--spacing-08) auto auto;
|
||||||
|
max-width: 400px;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
img,
|
||||||
|
.file-view-pdf {
|
||||||
|
max-width: 100%;
|
||||||
|
max-height: 90%;
|
||||||
|
display: block;
|
||||||
|
margin: var(--spacing-05) auto auto;
|
||||||
|
border: 1px solid var(--neutral-60);
|
||||||
|
box-shadow: 0 2px 3px var(--neutral-60);
|
||||||
|
background-color: var(--white);
|
||||||
|
}
|
||||||
|
|
||||||
|
.file-view-pdf {
|
||||||
|
overflow: auto;
|
||||||
|
width: max-content;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
.pdf-page:not(:last-of-type) {
|
||||||
|
border-bottom: 1px solid var(--neutral-60);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.linked-file-icon {
|
||||||
|
color: var(--blue-50);
|
||||||
|
}
|
||||||
|
|
||||||
|
.no-preview {
|
||||||
|
color: var(--neutral-60);
|
||||||
|
font-size: var(--font-size-06);
|
||||||
|
margin-top: var(--spacing-06);
|
||||||
|
}
|
||||||
|
|
||||||
|
.text-preview {
|
||||||
|
margin-top: var(--spacing-05);
|
||||||
|
|
||||||
|
.scroll-container {
|
||||||
|
background-color: var(--white);
|
||||||
|
font-size: 0.8em;
|
||||||
|
line-height: 1.1em;
|
||||||
|
overflow: auto;
|
||||||
|
border: 1px solid var(--neutral-30);
|
||||||
|
padding: var(--spacing-04) var(--spacing-05);
|
||||||
|
text-align: left;
|
||||||
|
white-space: pre;
|
||||||
|
font-family: monospace;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.full-size,
|
||||||
|
.loading-panel {
|
||||||
|
position: absolute;
|
||||||
|
inset: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.no-history-available,
|
||||||
|
.no-file-selection-message,
|
||||||
|
.multi-selection-message {
|
||||||
|
width: 50%;
|
||||||
|
margin: var(--spacing-10) auto;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pdf-empty,
|
||||||
|
.no-history-available,
|
||||||
|
.no-file-selection,
|
||||||
|
.multi-selection-ongoing {
|
||||||
|
&::before {
|
||||||
|
@extend .full-size;
|
||||||
|
|
||||||
|
left: 20px;
|
||||||
|
content: '';
|
||||||
|
background: url(../../../../../public/img/ol-brand/overleaf-o-grey.svg)
|
||||||
|
center / 200px no-repeat;
|
||||||
|
opacity: 0.2;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
}
|
|
@ -48,7 +48,7 @@ describe('<FileView/>', function () {
|
||||||
renderWithEditorContext(<FileView file={textFile} />)
|
renderWithEditorContext(<FileView file={textFile} />)
|
||||||
|
|
||||||
await waitForElementToBeRemoved(() =>
|
await waitForElementToBeRemoved(() =>
|
||||||
screen.getByText('Loading', { exact: false })
|
screen.getByTestId('loading-panel-file-view')
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -70,7 +70,7 @@ describe('<FileView/>', function () {
|
||||||
it('shows a loading indicator while the file is loading', async function () {
|
it('shows a loading indicator while the file is loading', async function () {
|
||||||
renderWithEditorContext(<FileView file={imageFile} />)
|
renderWithEditorContext(<FileView file={imageFile} />)
|
||||||
|
|
||||||
screen.getByText('Loading', { exact: false })
|
screen.getByTestId('loading-panel-file-view')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('shows messaging if the image could not be loaded', async function () {
|
it('shows messaging if the image could not be loaded', async function () {
|
||||||
|
|
Loading…
Reference in a new issue