pdf-preview.stories.js 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365
  1. import { useCallback, useMemo, useState } from 'react'
  2. import useFetchMock from './hooks/use-fetch-mock'
  3. import { Button } from 'react-bootstrap'
  4. import PdfPreviewPane from '../js/features/pdf-preview/components/pdf-preview-pane'
  5. import PdfPreview from '../js/features/pdf-preview/components/pdf-preview'
  6. import PdfFileList from '../js/features/pdf-preview/components/pdf-file-list'
  7. import { buildFileList } from '../js/features/pdf-preview/util/file-list'
  8. import PdfLogsViewer from '../js/features/pdf-preview/components/pdf-logs-viewer'
  9. import PdfPreviewError from '../js/features/pdf-preview/components/pdf-preview-error'
  10. import PdfPreviewHybridToolbar from '../js/features/pdf-preview/components/pdf-preview-hybrid-toolbar'
  11. import { useDetachCompileContext as useCompileContext } from '../js/shared/context/detach-compile-context'
  12. import {
  13. dispatchDocChanged,
  14. mockBuildFile,
  15. mockClearCache,
  16. mockCompile,
  17. mockCompileError,
  18. mockCompileValidationIssues,
  19. mockEventTracking,
  20. outputFiles,
  21. } from './fixtures/compile'
  22. import { cloneDeep } from 'lodash'
  23. import { ScopeDecorator } from './decorators/scope'
  24. export default {
  25. title: 'Editor / PDF Preview',
  26. component: PdfPreview,
  27. subcomponents: {
  28. PdfPreviewHybridToolbar,
  29. PdfFileList,
  30. PdfPreviewError,
  31. },
  32. decorators: [ScopeDecorator],
  33. }
  34. export const Interactive = () => {
  35. useFetchMock(fetchMock => {
  36. mockCompile(fetchMock)
  37. mockBuildFile(fetchMock)
  38. mockClearCache(fetchMock)
  39. })
  40. const Inner = () => {
  41. const context = useCompileContext()
  42. const { setHasLintingError } = context
  43. const toggleLintingError = useCallback(() => {
  44. setHasLintingError(value => !value)
  45. }, [setHasLintingError])
  46. const values = useMemo(() => {
  47. const entries = Object.entries(context).sort((a, b) => {
  48. return a[0].localeCompare(b[0])
  49. })
  50. const values = { boolean: [], other: [] }
  51. for (const entry of entries) {
  52. const type = typeof entry[1]
  53. if (type === 'boolean') {
  54. values.boolean.push(entry)
  55. } else if (type !== 'function') {
  56. values.other.push(entry)
  57. }
  58. }
  59. return values
  60. }, [context])
  61. return (
  62. <div
  63. style={{
  64. padding: 20,
  65. background: 'white',
  66. float: 'left',
  67. zIndex: 10,
  68. position: 'absolute',
  69. top: 60,
  70. bottom: 60,
  71. right: 20,
  72. left: 400,
  73. overflow: 'hidden',
  74. boxShadow: '0px 2px 5px #ccc',
  75. borderRadius: 3,
  76. }}
  77. >
  78. <div
  79. style={{
  80. display: 'flex',
  81. fontSize: 14,
  82. gap: 20,
  83. height: '100%',
  84. overflow: 'hidden',
  85. }}
  86. >
  87. <div style={{ height: '100%', overflow: 'auto', flexShrink: 0 }}>
  88. <table>
  89. <tbody>
  90. {values.boolean.map(([key, value]) => {
  91. return (
  92. <tr key={key} style={{ border: '1px solid #ddd' }}>
  93. <td style={{ padding: 5 }}>{value ? '🟢' : '🔴'}</td>
  94. <th style={{ padding: 5 }}>{key}</th>
  95. </tr>
  96. )
  97. })}
  98. </tbody>
  99. </table>
  100. <div>
  101. <div
  102. style={{
  103. display: 'flex',
  104. flexDirection: 'column',
  105. gap: 10,
  106. margin: '10px 0',
  107. }}
  108. >
  109. <Button onClick={dispatchDocChanged}>trigger doc change</Button>
  110. <Button onClick={toggleLintingError}>
  111. toggle linting error
  112. </Button>
  113. </div>
  114. </div>
  115. </div>
  116. <div style={{ height: '100%', overflow: 'auto' }}>
  117. <table
  118. style={{
  119. width: '100%',
  120. overflow: 'hidden',
  121. }}
  122. >
  123. <tbody>
  124. {values.other.map(([key, value]) => {
  125. return (
  126. <tr
  127. key={key}
  128. style={{
  129. width: '100%',
  130. overflow: 'hidden',
  131. border: '1px solid #ddd',
  132. }}
  133. >
  134. <th
  135. style={{
  136. verticalAlign: 'top',
  137. padding: 5,
  138. }}
  139. >
  140. {key}
  141. </th>
  142. <td
  143. style={{
  144. overflow: 'auto',
  145. padding: 5,
  146. }}
  147. >
  148. <pre
  149. style={{
  150. margin: '0 10px',
  151. fontSize: 10,
  152. }}
  153. >
  154. {JSON.stringify(value, null, 2)}
  155. </pre>
  156. </td>
  157. </tr>
  158. )
  159. })}
  160. </tbody>
  161. </table>
  162. </div>
  163. </div>
  164. </div>
  165. )
  166. }
  167. return (
  168. <div className="pdf-viewer">
  169. <PdfPreviewPane />
  170. <Inner />
  171. </div>
  172. )
  173. }
  174. const compileStatuses = [
  175. 'autocompile-backoff',
  176. 'clear-cache',
  177. 'clsi-maintenance',
  178. 'compile-in-progress',
  179. 'exited',
  180. 'failure',
  181. 'generic',
  182. 'project-too-large',
  183. 'rate-limited',
  184. 'success',
  185. 'terminated',
  186. 'timedout',
  187. 'too-recently-compiled',
  188. 'unavailable',
  189. 'validation-problems',
  190. 'foo',
  191. ]
  192. export const CompileError = () => {
  193. const [status, setStatus] = useState('success')
  194. useFetchMock(fetchMock => {
  195. mockCompileError(fetchMock, status, 0)
  196. mockBuildFile(fetchMock)
  197. })
  198. const Inner = () => {
  199. const { startCompile } = useCompileContext()
  200. const handleStatusChange = useCallback(
  201. event => {
  202. setStatus(event.target.value)
  203. window.setTimeout(() => {
  204. startCompile()
  205. }, 0)
  206. },
  207. [startCompile]
  208. )
  209. return (
  210. <div
  211. style={{
  212. position: 'absolute',
  213. bottom: 10,
  214. left: 10,
  215. background: 'white',
  216. padding: 10,
  217. }}
  218. >
  219. <label>
  220. {'status: '}
  221. <select value={status} onInput={handleStatusChange}>
  222. {compileStatuses.map(status => (
  223. <option key={status}>{status}</option>
  224. ))}
  225. </select>
  226. </label>
  227. </div>
  228. )
  229. }
  230. return (
  231. <>
  232. <PdfPreviewPane />
  233. <Inner />
  234. </>
  235. )
  236. }
  237. const compileErrors = [
  238. 'autocompile-backoff',
  239. 'clear-cache',
  240. 'clsi-maintenance',
  241. 'compile-in-progress',
  242. 'exited',
  243. 'failure',
  244. 'generic',
  245. 'project-too-large',
  246. 'rate-limited',
  247. 'success',
  248. 'terminated',
  249. 'timedout',
  250. 'too-recently-compiled',
  251. 'unavailable',
  252. 'validation-problems',
  253. 'foo',
  254. ]
  255. export const DisplayError = () => {
  256. useFetchMock(fetchMock => {
  257. mockCompile(fetchMock)
  258. })
  259. return (
  260. <>
  261. {compileErrors.map(error => (
  262. <div
  263. key={error}
  264. style={{ background: '#5d6879', padding: 10, margin: 5 }}
  265. >
  266. <div style={{ fontFamily: 'monospace', color: 'white' }}>{error}</div>
  267. <PdfPreviewError error={error} />
  268. </div>
  269. ))}
  270. </>
  271. )
  272. }
  273. export const HybridToolbar = () => {
  274. useFetchMock(fetchMock => {
  275. mockCompile(fetchMock, 500)
  276. mockBuildFile(fetchMock)
  277. mockEventTracking(fetchMock)
  278. })
  279. return (
  280. <div className="pdf">
  281. <PdfPreviewHybridToolbar />
  282. </div>
  283. )
  284. }
  285. export const FileList = () => {
  286. const fileList = useMemo(() => {
  287. return buildFileList(cloneDeep(outputFiles))
  288. }, [])
  289. return (
  290. <div className="dropdown open">
  291. <div className="dropdown-menu">
  292. <PdfFileList fileList={fileList} />
  293. </div>
  294. </div>
  295. )
  296. }
  297. export const Logs = () => {
  298. useFetchMock(fetchMock => {
  299. mockCompileError(fetchMock, 400, 0)
  300. mockBuildFile(fetchMock)
  301. mockClearCache(fetchMock)
  302. })
  303. return (
  304. <div className="pdf">
  305. <PdfLogsViewer />
  306. </div>
  307. )
  308. }
  309. const validationProblems = {
  310. sizeCheck: {
  311. resources: [
  312. { path: 'foo/bar', kbSize: 76221 },
  313. { path: 'bar/baz', kbSize: 2342 },
  314. ],
  315. },
  316. mainFile: true,
  317. conflictedPaths: [
  318. {
  319. path: 'foo/bar',
  320. },
  321. {
  322. path: 'foo/baz',
  323. },
  324. ],
  325. }
  326. export const ValidationIssues = () => {
  327. useFetchMock(fetchMock => {
  328. mockCompileValidationIssues(fetchMock, validationProblems, 0)
  329. mockBuildFile(fetchMock)
  330. })
  331. return <PdfPreviewPane />
  332. }