Skip to content

[stable35] Refactor version comparison - #9386

Open
backportbot[bot] wants to merge 19 commits into
stable35from
backport/9293/stable35
Open

backportbot[bot] wants to merge 19 commits into
stable35from
backport/9293/stable35

Conversation

@backportbot

@backportbot backportbot Bot commented Oct 14, 2026 •

Copy link
Copy Markdown

Backport of #9293

Warning, This backport had conflicts that were resolved with the ours merge strategy and is likely incomplete ⚠️

Todo

  • Review and resolve any conflicts
  • Amend HEAD commit to remove the line stating to skip CI

Learn more about backports at https://docs.nextcloud.com/server/stable/go.php?to=developer-backports.

@backportbot backportbot Bot added this to the Nextcloud 35.0.2 milestone Oct 14, 2026
mejo- added 19 commits October 14, 2026 14:15
The comparison Playwright suite did not exercise the app. It loaded the
login page, injected the built bundle, replaced the document body and
mounted the comparison factory directly, with patched observers and
forced failures. It needed three extra Playwright projects, an
environment switch in the config, a unit test of that config and the
axe-core dependency.

Remove it along with the config and workflow changes it required. The
comparison gets a real end-to-end test through the Viewer version
comparison in a later commit.

Signed-off-by: Jonas <jonas@freesources.org>
Assisted-by: ClaudeCode:claude-opus-5-5
The literal source comparison ran a line diff in a module worker with
cancellation, gap paging, word-level emphasis under time budgets and
visible tokens for control characters and line endings. That is a lot
of machinery for a view the rendered comparison rarely needs.

Remove the view, its worker and the worker build config. The plain
source fallback stays for the case where no rendered comparison can be
built; it now shows both snapshots verbatim without display limits.

Signed-off-by: Jonas <jonas@freesources.org>
Assisted-by: ClaudeCode:claude-opus-5-5
Add compareDocuments, which aligns sibling nodes with an array diff on
node equality, pairs the differing nodes positionally and compares
paired textblocks with prosemirror-changeset. Attribute changes are
reported for a small set of known attributes, everything else is text,
formatting or structure.

The accompanying decoration plugin highlights one side of the changes
and the editor helper loads content through setContent so text
direction is inferred like in every other editor.

This does not replace the existing model yet; the components move over
in the next commit.

Signed-off-by: Jonas <jonas@freesources.org>
Assisted-by: ClaudeCode:claude-opus-5-5
Rewrite MarkdownContentComparison and ComparisonChangeList on top of
compareDocuments and remove the previous model, its presentation
helpers and their tests.

The change list groups rows by the nearest heading and shows a label
with before and after previews. The document panes highlight the
changes through the decoration plugin, scroll to the current change
and stack below 760px through a container query instead of a resize
observer. The factory mounts the component and returns a destroy
handle; a failing or oversized comparison falls back to plain source.

Signed-off-by: Jonas <jonas@freesources.org>
Assisted-by: ClaudeCode:claude-opus-5-5
The comparison editors no longer need special treatment in RichText:
they load content through setContent, so the text direction plugin
infers paragraph direction like everywhere else, and duplicate heading
anchors in two read-only panes are harmless. Keymap and Search do
nothing in a non-editable editor, so registering them unconditionally
restores the previous behaviour for RichTextReader as well.

Inline the Markdown rendering helper into useEditorMethods again, as
nothing else uses it.

Signed-off-by: Jonas <jonas@freesources.org>
Assisted-by: ClaudeCode:claude-opus-5-5
Viewer's "Compare to current version" renders Text's viewer component
for the older version next to the current file. For Markdown files the
older version's component now loads both versions and shows the
comparison instead, and the sibling pane with the current file's editor
is hidden. Plain text files keep the side-by-side view.

Adjust the versions end-to-end test to expect the comparison.

Signed-off-by: Jonas <jonas@freesources.org>
Assisted-by: ClaudeCode:claude-opus-5-5
Viewer creates a new file object when the same file is opened again,
which happens when a version comparison starts, and the new object
starts with loaded set to false. The component is kept because its key
is unchanged, so nothing reported loaded again and the loading spinner
stayed on top of the comparison. Watch the flag passed by Viewer and
report loaded once more when it drops after the content has loaded.

Signed-off-by: Jonas <jonas@freesources.org>
Assisted-by: ClaudeCode:claude-opus-5.5
Reviewers want to see the documents side by side before drilling into
the list of changes.

Fixes: #4422

Signed-off-by: Jonas <jonas@freesources.org>
Assisted-by: ClaudeCode:claude-opus-5-5
Pair the top-level blocks of both documents, measure their rendered
offsets and pad the side whose block sits higher with a widget
decoration, so unchanged content stays level across the two panes
even when blocks were inserted or removed. Measuring includes the
spacers already in place, so a second round settles margin effects.
The panes re-align on resize and after images load.

Signed-off-by: Jonas <jonas@freesources.org>
Assisted-by: ClaudeCode:claude-opus-5-5
Mirror the scroll offset between the two panes, which line up block
by block since the previous commit. Jumping to a change scrolls one
pane and lets the other follow. Smooth scrolling is dropped because
mirroring an animated scroll feeds intermediate positions back.

Signed-off-by: Jonas <jonas@freesources.org>
Assisted-by: ClaudeCode:claude-opus-5-5
Spacers picked up the editor's styling for divs and could not render
below 34px, so small corrections never settled. Images that appear
after loading also grew a table after the last alignment. Reset the
spacer box and re-align whenever either document's size changes.

Signed-off-by: Jonas <jonas@freesources.org>
Assisted-by: ClaudeCode:claude-opus-5-5
Fixes version comparison in Collectives app.

Signed-off-by: Jonas <jonas@freesources.org>
Assisted-by: ClaudeCode:claude-opus-5-5
The border now uses the color of the change type: green for added, red
for removed, orange for attribute changes. This also fixes attribute
changes on blocks, where the neutral border overrode the orange
underline.

Signed-off-by: Jonas <jonas@freesources.org>
Assisted-by: ClaudeCode:claude-opus-5-5
Aligning blocks by equality alone picks arbitrary matches among
similar-looking paragraphs, so a paragraph split around an image
showed up as one paragraph added and others removed.

Blocks that are equal and unique on both sides anchor the alignment.
The blocks between two anchors are paired by text similarity, shared
words or a shared start and end, so edited and split paragraphs pair
with their origin. This replaces the array diff, so the diff package
is no longer needed.

Signed-off-by: Jonas <jonas@freesources.org>
Assisted-by: ClaudeCode:claude-opus-5-5
Signed-off-by: Jonas <jonas@freesources.org>
Assisted-by: ClaudeCode:claude-opus-5-5
Each node is fingerprinted at most once per comparison, and the after
document is rebuilt on every call, so the fingerprint cache never got
a hit. Compute the fingerprint directly instead.

Also replace code for "middle between two numbers rounded down" with
an alternative that's easier to parse.

Also add better documentation to some functions.

Signed-off-by: Jonas <jonas@freesources.org>
Assisted-by: ClaudeCode:claude-opus-5-5
Introduce a Gap type and gapsBetween() so alignChildren() and
compareChildren() share one definition of the unmatched children
between matches, instead of each tracking positions by hand with a
sentinel match. Split similarity() into sharedWords() and
sharedEdges().

Describe the anchor and gap steps in compareDocuments() and clarify
the ChangeCategory and MIN_SIMILARITY comments.

Signed-off-by: Jonas <jonas@freesources.org>
Assisted-by: ClaudeCode:claude-opus-5-5
Move what the views of a comparison share out of MarkdownContentComparison
into a comparison session: the editors of both sides, the changes,
the current one and the formatting filter, and the alignment and
synchronised scrolling of the documents. The document of each side,
the filter, the change navigation and the list of changes become
components of their own working on a session, so the two documents
can also be shown by different components.

MarkdownContentComparison is built from these parts and behaves as
before.

Signed-off-by: Jonas <jonas@freesources.org>
Assisted-by: ClaudeCode:claude-opus-5-5
A spacer element of the needed height before a block stopped the
block's top margin from collapsing with the bottom margin above it, so
the block moved by the spacer plus the smaller margin. Where that
margin was larger than the correction, typically before a heading, the
documents never lined up: each round overshot and the next corrected
on the other side, and the panes kept jumping.

Set the block's top margin to the measured gap above it plus the
spacer instead. The margins still collapse, and the block moves by
exactly the spacer.

Signed-off-by: Jonas <jonas@freesources.org>
Assisted-by: ClaudeCode:claude-opus-5-5
@mejo-
mejo- force-pushed the backport/9293/stable35 branch from 996ae45 to 44c4e54 Compare October 14, 2026 13:26
@mejo- mejo- moved this from 🧭 Planning evaluation (don't pick) to 🏗️ In progress in 📝 Productivity team Oct 14, 2026
@mejo-
mejo- marked this pull request as ready for review October 14, 2026 13:26
@mejo-
mejo- requested a review from max-nextcloud as a code owner October 14, 2026 13:26
@mejo- mejo- changed the title [stable35] test(comparison): drop the Playwright comparison harness [stable35] Refactor version comparison - #9293 Oct 14, 2026
@mejo- mejo- changed the title [stable35] Refactor version comparison - #9293 [stable35] Refactor version comparison Oct 14, 2026
@mejo- mejo- moved this from 🏗️ In progress to 👀 In review in 📝 Productivity team Oct 14, 2026

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

Status: 👀 In review

Development

Successfully merging this pull request may close these issues.

1 participant