Migrate content viewer to React - #200
dominickendrick wants to merge 7 commits into
Conversation
| // LinkButton renders an <a> (content-box) while Button renders a <button> | ||
| // (border-box), so the shared explicit height makes links taller. Force | ||
| // border-box to match the buttons. | ||
| const linkButtonBoxSizing = css({ |
There was a problem hiding this comment.
We should push this change back to Stand.
There was a problem hiding this comment.
Yeah, I can't see that they ship a CSS reset but it definitely applies here!
| // write succeeds and can be read back in the assertion below. | ||
| await page | ||
| .context() | ||
| .grantPermissions(["clipboard-read", "clipboard-write"]); |
| * Render a snapshot's article body from its flattened list of elements, | ||
| * replacing the single `getHTMLContent` HTML string the legacy model produced. | ||
| */ | ||
| const ArticleBody: FunctionComponent<ArticleBodyProps> = ({ elements }) => { |
There was a problem hiding this comment.
Ooh, do we have alignment on whether a single export at the bottom of the file, or inline exports export const ArticleBody, is preferable? Tools' usage of these styles vary. My e2e infra code almost exclusively uses inline exports. Don't have a super strong opinion on style, but it'd be nice to have consistency
There was a problem hiding this comment.
Yeah, I feel like inline exports are clearer to read when scanning the code. Updated in 3b6f529
| // LinkButton renders an <a> (content-box) while Button renders a <button> | ||
| // (border-box), so the shared explicit height makes links taller. Force | ||
| // border-box to match the buttons. | ||
| const linkButtonBoxSizing = css({ |
There was a problem hiding this comment.
Yeah, I can't see that they ship a CSS reset but it definitely applies here!
| }; | ||
|
|
||
| // Prefer the async Clipboard API (the modern, standard approach), falling back | ||
| // to a hidden textarea + `execCommand` for non-secure contexts where |
There was a problem hiding this comment.
This fallback shouldn't be necessary AFAICS — writeText has been around for a very long time
| }; | ||
| }; | ||
|
|
||
| type RawListItem = { |
There was a problem hiding this comment.
It's brutal that we're defining types here, rather than integrating them from the writer upstream (which could I guess derive a great deal from flexible-model?), but I get that we have to start somewhere — wonder how we might share type information here, and who owns it 🤔
|
|
||
| /** Subscribe to the request to show the rendered HTML view. */ | ||
| const subscribeDisplayHtml = (callback: () => void): (() => void) => { | ||
| const handler = (): void => callback(); |
There was a problem hiding this comment.
Wonder why an intermediate handler is necessary here, mediator.subscribe(CHANNELS.displayHtml, callback); is identical other than the this context IIUC. Not blocking, as we expect this code to go
|
(Can't wait to tear out the event bus 😅) |
050302b to
5f7d3d3
Compare
5f7d3d3 to
c5573f5
Compare
Hide the content panel immediately when the selected version changes and render furniture/panels only after content is available, eliminating visual jank for both mouse and keyboard navigation.
c2531e2 to
bf9f544
Compare
…s supported in all modern browsers our editors use
These were fixed in bf9f544 great spot !! |




Note
This PR contains code generated by AI using Claude Opus 4.8. This was all reviewed by developers
What does this change?
This is the next step of the AngularJS → React migration described in
rfc/react-frontend-migration.md. It migrates the snapshot content viewer (the article furniture, the sliding HTML/JSON body and the Restore / Copy / Export / toggle actions bar) to React, following the incremental bridge pattern established for the search form and sidebar. The rest of the AngularJS app keeps running unchanged.The still-Angular
SnapshotListCtrlremains authoritative for the active selection; the new React viewer loads the initial snapshot itself and then follows the existingsnapshot-list:*mediator events, so keyboard navigation and the HTML/JSON toggle stay in sync across the Angular ↔ React boundary.Migrated components
ContentViewer— replaces thesnapshot-contentblock ofrestore-list.htmlandSnapshotContentCtrl, composed of:ContentActions— the Restore / Copy JSON / Export (Git & Zip) / Show JSON-Text toggle bar, using StandButton/LinkButton.ContentFurniture— the headline / standfirst / trailText summary.ContentPanels— the 200%-wide sliding track holding the HTML and JSON columns.article/*(ArticleBody,ArticleElementView,ListElementView,TimelineElementView,RawHtml) — renders the parsed article body.useSnapshotContenthook that portsSnapshotContentCtrl's behaviour: initial (index 0) load, followingsnapshot-list:load-content, HTML/JSON toggle round-tripped through the mediator, the fade-in on content change, restore-permission check, and copy-to-clipboard.snapshotContentmodel (parseSnapshotContent) plus unit tests, replacingSnapshotModel.js.fetchSnapshotAPI layer, replacing the legacySnapshotService/SnapshotModels.Clipboard
navigator.clipboard.writeText) in secure contexts, falling back to the legacy hidden-textarea +execCommand("copy")for insecure contexts.React ↔ Angular bridge
<snapshot-content-viewer>directive viareact2angular(components/index.js) and swaps it intorestore-list.htmlin place of the Angular content block.Styling
snapshot-content.scss,scrollable.scssand the content-viewer parts oftext.scssto Emotion (css), and adds sharedstyles/palette.ts/styles/icons.ts. Removes the now-unused SCSS imports fromindex.scss.Removals
SnapshotContentCtrl.js,SnapshotModel.js,SnapshotModels.jsandSnapshotCollectionService.js(and removes them from the controllers/models/services/collections indexes).SnapshotServicedependency fromSnapshotListCtrl.Tooling / build
html-react-parser(article HTML → React) and@types/jest.testMatchto include.ts/.tsxand runsbddgenbeforenpm run test.Local dev / e2e
npm run dev:localnow streams container logs to the terminal and surfaceslogs/application.logon the host (via a newmountLogsoption instartLocalStack), with the log mount kept out of the parallel e2e suite.How has this change been tested?
npm run test) exercises snapshot content, the HTML/JSON toggle, Copy JSON, export links and the restore flow, all of which now run against the migrated React viewer.snapshotContentmodel (npm run test:unit).npm run dev:local:How can we measure success?