Skip to content

chore: For v1.33.0 release - #786

Merged
surajshetty3416 merged 927 commits into
frappe:masterfrom
surajshetty3416:for-release-v1.33.0
Aug 28, 2026
Merged

chore: For v1.33.0 release#786
surajshetty3416 merged 927 commits into
frappe:masterfrom
surajshetty3416:for-release-v1.33.0

Conversation

@surajshetty3416

@surajshetty3416 surajshetty3416 commented Aug 28, 2026

Copy link
Copy Markdown
Member

Bob, the AI assistant

Builder gets a chat assistant that builds and edits pages directly on the canvas (#671). Bob orients itself in the site on demand, reads existing pages as references, researches online when it needs to, and works with the component system, props and bindings. The canvas follows along as it builds, and cancelling mid-generation keeps whatever has landed so far.

Design Tokens

Builder Variable is now Builder Token, with Font and Dimension tokens alongside colours (#676). Font tokens pick their value from the font dropdown, which previews every family, and every token row, in its own typeface.

Translatable UI

The editor is translatable end to end (#706, #721): user-facing strings are wrapped, translations are served from boot data, and 35 language catalogs are synced from Crowdin.

Image controls

Cover images get a focus point control with zoom crop and a visible-part frame, inside a redesigned image popover that the background tab now shares (#768). Stored images are capped at 2048px on the long edge, and a pasted page brings its images and fonts into the site with it.

Editor

Fixes and maintenance

surajshetty3416 and others added 21 commits August 20, 2026 18:42
…-sync

fix: sync the root lockfile with the workspace manifests
The chart has been blank since 9afded2 (frappe#728) resolved echarts to 6.1.0
over the ^5.6.0 frappe-ui asks for. frappe-ui always emits
`color: config.colors`, and no caller here sets `colors`; echarts 5
ignored the resulting `color: undefined` and kept its own palette, echarts
6 lets the key win, so every series drew with no fill and no stroke while
the axes, legend and tooltip carried on as usual.

Pin the series colors, and fix what became visible with them:

- style the axes through `xAxis.echartOptions` / `yAxis.echartOptions`. A
  top-level `echartOptions.yAxis` array replaces frappe-ui's own axis
  config rather than merging into it, which is why the left axis was blank
  and ticks read `4,000` instead of `4K`.
- drop the y2 axis and its "Timeline" title. Both series count views, so
  they belong on one axis.
- repeat the color in each series' emphasis state. echarts derives the
  hover color by parsing the series color, cannot parse a css var, and
  paints nothing, so hovering wiped the chart.
- drop the chart's padding and the negative margin that compensated for
  it. zrender sizes the svg minus padding but positions it at the padding
  box, so padding offsets pointer hit-testing and swallowed the
  click-to-drill-down.

Co-Authored-By: Claude <noreply@anthropic.com>
…t-colors

fix(analytics): restore the site analytics chart under echarts 6
Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
CodeMirrorEditor created an EditorView in onMounted but never destroyed
it. CodeMirror does not release its view tree, DOM or document observer
on its own, so every remount leaked the whole editor and left its
DOMObserver polling the selection.

Selecting a block that has innerHTML mounts this editor on the block's
raw source in the HTML Options panel, so working with such a block leaked
continuously. On a page whose block held a 205 KB inline SVG, 20 rounds
of select, copy, delete and paste grew the tab by 56,420 DOM nodes and
12,633 event listeners, none of which a forced GC reclaimed. The same run
with the view destroyed grows by zero.

Co-Authored-By: Claude <noreply@anthropic.com>
Every history record is a full serialisation of the block tree, so a heavy
page reached hundreds of MB long before it reached the 500 entry cap. On a
743 KB page each edit cost 1.55 MB and the stack was heading for roughly
775 MB before it would evict anything.

Cap on total bytes as well, whichever limit is hit first, keeping a floor of
10 entries so undo stays usable on a page too big for the budget. The same
trim runs on redo. Measured over 120 edits the stack now settles at 29
entries and 20.6 MB, and the cost per edit drops from 1.55 MB to 0.35 MB.

Also copy the selection into each record. It stored the live set by
reference, so every stacked entry tracked the current selection instead of
the one it was taken with, and undo restored the wrong blocks.

Co-Authored-By: Claude <noreply@anthropic.com>
An inline SVG lives in the page JSON, so it is re-serialised on every save,
walked by every deep watcher and copied into every history entry. Figma
exports are routinely hundreds of KB, and one page here carried 645 KB of
inline SVG across five blocks, 87% of its total weight.

Pasting an SVG over 20 KB now asks whether to upload it as a file and
reference it, or keep it inline. Taking the offer moves it out of the page
entirely and lets the browser cache it: a 68 KB paste leaves zero inline
bytes behind and becomes an image block that keeps the SVG's own width and
height.

An SVG that paints from a Builder token is never offered, because an <img>
cannot read CSS variables and the theming would break. Both paste routes are
covered, whether the SVG lands in a new block or replaces the content of an
HTML block that is already selected.

Co-Authored-By: Claude <noreply@anthropic.com>
…xt menu

Pasting now offers to upload a large SVG, but pages built before that still
carry theirs inline. One page here holds 653 KB of inline SVG across 34
blocks, 87% of its weight, and there was no way to get it out.

Adds "Upload SVG as File" to the block context menu, offered only on an SVG
block big enough to be worth moving. The block keeps its id, position and
styles and simply repoints at the uploaded file, so nothing downstream has
to move. Converting the largest block on that page took the inline total
from 653,863 to 449,170 bytes.

The intrinsic size is read off the <svg> tag before it leaves the page and
applied only where the block has no size of its own, and object-fit is set
to contain: an inline <svg> letterboxes inside its box by default while an
<img> stretches, so without it the artwork would skew on conversion.

Co-Authored-By: Claude <noreply@anthropic.com>
The context menu already offered this, but the panel is where you are when
you are looking at a block's inline SVG, and there was nothing there. A
205 KB SVG showed its source in the code editor with no hint that it could
be moved out of the page.

Adds a "Convert to Image File (200 KB)" button under the HTML editor,
showing the size so the cost is visible, and renames the context menu entry
to match so one action is not called two different things.

Co-Authored-By: Claude <noreply@anthropic.com>
Measured it: converting the five big SVGs on a 743 KB page leaves per-edit
time unchanged (~66 ms either way). Vue's deep-watch traverse does not
descend into strings, so a large innerHTML is one property either way. The
wins are autosave payload, history size and canvas DOM, not watcher cost.

Co-Authored-By: Claude <noreply@anthropic.com>
getImageBlock supplies objectFit "cover" from the image template, and it was
spread after the block's own styles, so it won. An SVG whose viewBox aspect
differs from its width/height attributes was then cropped, where inline it
would have letterboxed. Verified with a 400x120 box around a 559x553 viewBox:
object-fit is now contain, matching convertSVGBlockToImage.

Reported by Greptile on frappe#784.

Co-Authored-By: Claude <noreply@anthropic.com>
onMounted awaits twice before constructing the view. If the component
unmounts in that window, onBeforeUnmount has already run and finds no editor
to destroy, and the continuation then builds one into a detached container
where nothing will ever dispose it.

Guarded with a disposed flag checked after the awaits.

I could not reproduce an actual leak from this, including a deterministic
mount/unmount race swept across 2-25 ms windows, most likely because
defineAsyncComponent means the inner component never mounts at all when the
parent unmounts first. Keeping it as a cheap guard against a real lifecycle
hazard rather than a measured fix.

Reported by Greptile on frappe#784.

Co-Authored-By: Claude <noreply@anthropic.com>
resetEditor guards on `editor` up front, then awaits createStartingState and
dereferences `editor` again for setState, focus and dom. Teardown can land in
that window, and since unmount now nulls the view, the continuation would
throw instead of quietly working on a stale one.

Reachable through PageClientScriptManager, whose selectScript is the only
caller passing resetHistory: true, which is the branch that awaits.

Re-checks after the await and returns early. Document swapping on the
non-awaiting path verified unchanged: switching between blocks still reuses
the same view and swaps the document.

Reported by Greptile on frappe#784.

Co-Authored-By: Claude <noreply@anthropic.com>
Most of what I added restated the code or explained rationale that belongs in
the commit history. Cut 24 comment lines to 8, keeping only the non-obvious
constraints: why a token-painted SVG stays inline, why object-fit is forced,
why the history record copies the selection, and the two async-teardown
guards.

Co-Authored-By: Claude <noreply@anthropic.com>
…tor-leak

fix(editor): stop the editor leaking memory, and stop pages carrying SVGs inline
feat: published status across dashboard and editor
@mergify

mergify Bot commented Aug 28, 2026

Copy link
Copy Markdown
Contributor

Tick the box to add this pull request to the merge queue (same as @mergifyio queue).

  • Queue this pull request

@codecov

codecov Bot commented Aug 28, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 66.32542% with 2171 lines in your changes missing coverage. Please review.
✅ Project coverage is 66.06%. Comparing base (5b10138) to head (9819a61).
⚠️ Report is 1 commits behind head on master.

Files with missing lines Patch % Lines
builder/ai/agent/loop.py 22.30% 519 Missing ⚠️
builder/ai/api.py 26.52% 241 Missing ⚠️
builder/ai/agent/artifact.py 41.17% 100 Missing ⚠️
builder/ai/codex_login.py 30.37% 94 Missing ⚠️
builder/ai/agent/tools/data.py 35.46% 91 Missing ⚠️
builder/ai/codex.py 72.55% 87 Missing ⚠️
builder/ai/agent/tools/conversation.py 16.66% 85 Missing ⚠️
builder/ai/session.py 51.44% 84 Missing ⚠️
builder/ai/agent/tools/query.py 71.42% 80 Missing ⚠️
builder/ai/agent/pending.py 20.40% 78 Missing ⚠️
... and 36 more
Additional details and impacted files
@@            Coverage Diff             @@
##           master     #786      +/-   ##
==========================================
+ Coverage   57.59%   66.06%   +8.47%     
==========================================
  Files          35       93      +58     
  Lines        4271    10386    +6115     
==========================================
+ Hits         2460     6862    +4402     
- Misses       1811     3524    +1713     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

surajshetty3416 and others added 4 commits August 28, 2026 15:02
export_dir_name scrubbed the name and replaced slashes, but let "." and
".." through as a whole segment. Route it through safe_segment, which
already guards the template fixture paths, and move that helper into
utils so both exporters share one implementation.

Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Claude <noreply@anthropic.com>
@surajshetty3416
surajshetty3416 merged commit 2ea28db into frappe:master Aug 28, 2026
10 checks passed
@github-actions

Copy link
Copy Markdown

🎉 This PR is included in version 1.33.0 🎉

The release is available on GitHub release

Your semantic-release bot 📦🚀

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

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants