mirror of
https://github.com/overleaf/overleaf.git
synced 2024-11-21 20:47:08 -05:00
30860ae9f9
* [web] Migrate Logs components JSX to Bootstrap 5 * [web] Migrate logs.less to logs.scss * [web] Remove unused class names * [storybook] Define default Bootstrap version in Storybook This prevents some warning in the console * [storybook] Update pdf-preview.stories.jsx * [storybook] Add pdf-log-entry.stories.tsx * [storybook] Force re-renders when switching BS version * [web] Keep files dropdown menu in bounds * [web] Make files dropdown items not bold in BS5 * [web] Revert unrelated change * [web] Fixup PreviewLogsPaneMaxEntries * [web] Add style for log-entry-content-link * [web] Replace log-entry by OLNotification in `PdfCodeCheckFailedNotice` * [web] Use `BootstrapVersionSwitcher` instead of `isBootstrap5` * [web] Rename `DropdownBS3` to `BS3Dropdown` * [web] Reuse variables for `toolbar-height` and `toolbar-small-height` * [web] Set `id` on `DropdownToggle` not `Dropdown` * [web] Set `log-entry-btn-expand-collapse` in BS3 only * [web] Remove `block: true` from StartFreeTrialButton in BS3 * [web] Remove unnecessary CSS in `.log-entry-header-link` * [web] Use semantic color names * Migrate the downloadable pdf file list to Bootstrap 5 * Remove nested BootstrapVersionSwitcher, fix "key" prop * Update roles to: `<li role="menuitem">` `<a role="link">` * Update `log-entry-header-link`: variant ghost and fix colors --------- Co-authored-by: Rebeka <o.dekany@gmail.com> GitOrigin-RevId: 89848970ab5d8a8c135335386caf24363f69a34c
388 lines
9.3 KiB
JavaScript
388 lines
9.3 KiB
JavaScript
import { useCallback, useMemo, useState } from 'react'
|
|
import useFetchMock from './hooks/use-fetch-mock'
|
|
import { Button } from 'react-bootstrap'
|
|
import PdfPreviewPane from '../js/features/pdf-preview/components/pdf-preview-pane'
|
|
import PdfPreview from '../js/features/pdf-preview/components/pdf-preview'
|
|
import PdfFileList from '../js/features/pdf-preview/components/pdf-file-list'
|
|
import { buildFileList } from '../js/features/pdf-preview/util/file-list'
|
|
import PdfLogsViewer from '../js/features/pdf-preview/components/pdf-logs-viewer'
|
|
import PdfPreviewError from '../js/features/pdf-preview/components/pdf-preview-error'
|
|
import PdfPreviewHybridToolbar from '../js/features/pdf-preview/components/pdf-preview-hybrid-toolbar'
|
|
import { useDetachCompileContext as useCompileContext } from '../js/shared/context/detach-compile-context'
|
|
import {
|
|
dispatchDocChanged,
|
|
mockBuildFile,
|
|
mockClearCache,
|
|
mockCompile,
|
|
mockCompileError,
|
|
mockCompileValidationIssues,
|
|
mockEventTracking,
|
|
outputFiles,
|
|
} from './fixtures/compile'
|
|
import { cloneDeep } from 'lodash'
|
|
import { ScopeDecorator } from './decorators/scope'
|
|
import { PdfPreviewProvider } from '@/features/pdf-preview/components/pdf-preview-provider'
|
|
import { bsVersionDecorator } from '../../.storybook/utils/with-bootstrap-switcher'
|
|
import {
|
|
Dropdown,
|
|
DropdownMenu,
|
|
} from '@/features/ui/components/bootstrap-5/dropdown-menu'
|
|
import BootstrapVersionSwitcher from '@/features/ui/components/bootstrap-5/bootstrap-version-switcher'
|
|
|
|
export default {
|
|
title: 'Editor / PDF Preview',
|
|
component: PdfPreview,
|
|
subcomponents: {
|
|
PdfPreviewHybridToolbar,
|
|
PdfFileList,
|
|
PdfPreviewError,
|
|
},
|
|
decorators: [ScopeDecorator],
|
|
argTypes: {
|
|
...bsVersionDecorator.argTypes,
|
|
},
|
|
}
|
|
|
|
export const Interactive = () => {
|
|
useFetchMock(fetchMock => {
|
|
mockCompile(fetchMock)
|
|
mockBuildFile(fetchMock)
|
|
mockClearCache(fetchMock)
|
|
})
|
|
|
|
const Inner = () => {
|
|
const context = useCompileContext()
|
|
|
|
const { setHasLintingError } = context
|
|
|
|
const toggleLintingError = useCallback(() => {
|
|
setHasLintingError(value => !value)
|
|
}, [setHasLintingError])
|
|
|
|
const values = useMemo(() => {
|
|
const entries = Object.entries(context).sort((a, b) => {
|
|
return a[0].localeCompare(b[0])
|
|
})
|
|
|
|
const values = { boolean: [], other: [] }
|
|
|
|
for (const entry of entries) {
|
|
const type = typeof entry[1]
|
|
|
|
if (type === 'boolean') {
|
|
values.boolean.push(entry)
|
|
} else if (type !== 'function') {
|
|
values.other.push(entry)
|
|
}
|
|
}
|
|
|
|
return values
|
|
}, [context])
|
|
|
|
return (
|
|
<div
|
|
style={{
|
|
padding: 20,
|
|
background: 'white',
|
|
float: 'left',
|
|
zIndex: 10,
|
|
position: 'absolute',
|
|
top: 60,
|
|
bottom: 60,
|
|
right: 20,
|
|
left: 400,
|
|
overflow: 'hidden',
|
|
boxShadow: '0px 2px 5px #ccc',
|
|
borderRadius: 3,
|
|
}}
|
|
>
|
|
<div
|
|
style={{
|
|
display: 'flex',
|
|
fontSize: 14,
|
|
gap: 20,
|
|
height: '100%',
|
|
overflow: 'hidden',
|
|
}}
|
|
>
|
|
<div style={{ height: '100%', overflow: 'auto', flexShrink: 0 }}>
|
|
<table>
|
|
<tbody>
|
|
{values.boolean.map(([key, value]) => {
|
|
return (
|
|
<tr key={key} style={{ border: '1px solid #ddd' }}>
|
|
<td style={{ padding: 5 }}>{value ? '🟢' : '🔴'}</td>
|
|
<th style={{ padding: 5 }}>{key}</th>
|
|
</tr>
|
|
)
|
|
})}
|
|
</tbody>
|
|
</table>
|
|
|
|
<div>
|
|
<div
|
|
style={{
|
|
display: 'flex',
|
|
flexDirection: 'column',
|
|
gap: 10,
|
|
margin: '10px 0',
|
|
}}
|
|
>
|
|
<Button onClick={dispatchDocChanged}>trigger doc change</Button>
|
|
<Button onClick={toggleLintingError}>
|
|
toggle linting error
|
|
</Button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div style={{ height: '100%', overflow: 'auto' }}>
|
|
<table
|
|
style={{
|
|
width: '100%',
|
|
overflow: 'hidden',
|
|
}}
|
|
>
|
|
<tbody>
|
|
{values.other.map(([key, value]) => {
|
|
return (
|
|
<tr
|
|
key={key}
|
|
style={{
|
|
width: '100%',
|
|
overflow: 'hidden',
|
|
border: '1px solid #ddd',
|
|
}}
|
|
>
|
|
<th
|
|
style={{
|
|
verticalAlign: 'top',
|
|
padding: 5,
|
|
}}
|
|
>
|
|
{key}
|
|
</th>
|
|
<td
|
|
style={{
|
|
overflow: 'auto',
|
|
padding: 5,
|
|
}}
|
|
>
|
|
<pre
|
|
style={{
|
|
margin: '0 10px',
|
|
fontSize: 10,
|
|
}}
|
|
>
|
|
{JSON.stringify(value, null, 2)}
|
|
</pre>
|
|
</td>
|
|
</tr>
|
|
)
|
|
})}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
)
|
|
}
|
|
|
|
return (
|
|
<div className="pdf-viewer">
|
|
<PdfPreviewPane />
|
|
<Inner />
|
|
</div>
|
|
)
|
|
}
|
|
|
|
const compileStatuses = [
|
|
'autocompile-backoff',
|
|
'clear-cache',
|
|
'clsi-maintenance',
|
|
'compile-in-progress',
|
|
'exited',
|
|
'failure',
|
|
'generic',
|
|
'project-too-large',
|
|
'rate-limited',
|
|
'success',
|
|
'terminated',
|
|
'timedout',
|
|
'too-recently-compiled',
|
|
'unavailable',
|
|
'validation-problems',
|
|
'foo',
|
|
]
|
|
|
|
export const CompileError = () => {
|
|
const [status, setStatus] = useState('success')
|
|
|
|
useFetchMock(fetchMock => {
|
|
mockCompileError(fetchMock, status, 0)
|
|
mockBuildFile(fetchMock)
|
|
})
|
|
|
|
const Inner = () => {
|
|
const { startCompile } = useCompileContext()
|
|
|
|
const handleStatusChange = useCallback(
|
|
event => {
|
|
setStatus(event.target.value)
|
|
window.setTimeout(() => {
|
|
startCompile()
|
|
}, 0)
|
|
},
|
|
[startCompile]
|
|
)
|
|
|
|
return (
|
|
<div
|
|
style={{
|
|
position: 'absolute',
|
|
bottom: 10,
|
|
left: 10,
|
|
background: 'white',
|
|
padding: 10,
|
|
}}
|
|
>
|
|
<label>
|
|
{'status: '}
|
|
<select value={status} onInput={handleStatusChange}>
|
|
{compileStatuses.map(status => (
|
|
<option key={status}>{status}</option>
|
|
))}
|
|
</select>
|
|
</label>
|
|
</div>
|
|
)
|
|
}
|
|
|
|
return (
|
|
<>
|
|
<PdfPreviewPane />
|
|
<Inner />
|
|
</>
|
|
)
|
|
}
|
|
|
|
const compileErrors = [
|
|
'autocompile-backoff',
|
|
'clear-cache',
|
|
'clsi-maintenance',
|
|
'compile-in-progress',
|
|
'exited',
|
|
'failure',
|
|
'generic',
|
|
'project-too-large',
|
|
'rate-limited',
|
|
'success',
|
|
'terminated',
|
|
'timedout',
|
|
'too-recently-compiled',
|
|
'unavailable',
|
|
'validation-problems',
|
|
'foo',
|
|
]
|
|
|
|
export const DisplayError = () => {
|
|
useFetchMock(fetchMock => {
|
|
mockCompile(fetchMock)
|
|
})
|
|
|
|
return (
|
|
<div className="logs-pane">
|
|
{compileErrors.map(error => (
|
|
<div
|
|
key={error}
|
|
style={{ background: '#5d6879', padding: 10, margin: 5 }}
|
|
>
|
|
<div style={{ fontFamily: 'monospace', color: 'white' }}>{error}</div>
|
|
<PdfPreviewError error={error} />
|
|
</div>
|
|
))}
|
|
</div>
|
|
)
|
|
}
|
|
|
|
export const HybridToolbar = () => {
|
|
useFetchMock(fetchMock => {
|
|
mockCompile(fetchMock, 500)
|
|
mockBuildFile(fetchMock)
|
|
mockEventTracking(fetchMock)
|
|
})
|
|
|
|
return (
|
|
<div className="pdf">
|
|
<PdfPreviewHybridToolbar />
|
|
</div>
|
|
)
|
|
}
|
|
|
|
export const FileList = () => {
|
|
const fileList = useMemo(() => {
|
|
return buildFileList(cloneDeep(outputFiles))
|
|
}, [])
|
|
|
|
return (
|
|
<BootstrapVersionSwitcher
|
|
bs3={
|
|
<div className="dropdown open">
|
|
<div className="dropdown-menu">
|
|
<PdfFileList fileList={fileList} />
|
|
</div>
|
|
</div>
|
|
}
|
|
bs5={
|
|
<Dropdown>
|
|
<DropdownMenu id="dropdown-files-logs-pane-list" show>
|
|
<PdfFileList fileList={fileList} />
|
|
</DropdownMenu>
|
|
</Dropdown>
|
|
}
|
|
/>
|
|
)
|
|
}
|
|
|
|
export const Logs = () => {
|
|
useFetchMock(fetchMock => {
|
|
mockCompileError(fetchMock, 400, 0)
|
|
mockBuildFile(fetchMock)
|
|
mockClearCache(fetchMock)
|
|
})
|
|
|
|
return (
|
|
<div className="pdf">
|
|
<PdfPreviewProvider>
|
|
<PdfLogsViewer />
|
|
</PdfPreviewProvider>
|
|
</div>
|
|
)
|
|
}
|
|
|
|
const validationProblems = {
|
|
sizeCheck: {
|
|
resources: [
|
|
{ path: 'foo/bar', kbSize: 76221 },
|
|
{ path: 'bar/baz', kbSize: 2342 },
|
|
],
|
|
},
|
|
mainFile: true,
|
|
conflictedPaths: [
|
|
{
|
|
path: 'foo/bar',
|
|
},
|
|
{
|
|
path: 'foo/baz',
|
|
},
|
|
],
|
|
}
|
|
|
|
export const ValidationIssues = () => {
|
|
useFetchMock(fetchMock => {
|
|
mockCompileValidationIssues(fetchMock, validationProblems, 0)
|
|
mockBuildFile(fetchMock)
|
|
})
|
|
|
|
return <PdfPreviewPane />
|
|
}
|