v0.7.58: styling improvements, files dimensions - #6303
Conversation
waleedlatif1
commented
Aug 6, 2026
- feat(library): Sim vs Dify: Open-Source AI Workspace vs LLM App / RAG Platform (feat(library): Sim vs Dify: Open-Source AI Workspace vs LLM App / RAG Platform #6286)
- feat(tables): support plain predicates in v2 queries (feat(tables): support plain predicates in v2 queries #6292)
- improvement(docs): restructure sidebar, align chrome, rename Mothership to Chat (improvement(docs): restructure sidebar, align chrome, rename Mothership to Chat #6296)
- fix(files): stop a cached collab snapshot resurrecting blank lines (fix(files): stop a cached collab snapshot resurrecting blank lines #6293)
- fix(editor): restore caret alignment and the intended type scale across the panel (fix(editor): restore caret alignment and the intended type scale across the panel #6297)
- improvement(tables): raise the max column limit to 1000 (improvement(tables): raise the max column limit to 1000 #6295)
- fix(knowledge): scroll the whole chunk editor area instead of the textarea (fix(knowledge): scroll the whole chunk editor area instead of the textarea #6300)
- fix(docs): stop the sidebar drifting when page content resizes (fix(docs): stop the sidebar drifting when page content resizes #6301)
- fix(files): reserve image layout space so images stop reflowing on load (fix(files): reserve image layout space so images stop reflowing on load #6299)
… Platform (#6286) * feat(library): Sim vs Dify: Open-Source AI Workspace vs LLM App / RAG Platform * feat(library): Sim vs Dify: Open-Source AI Workspace vs LLM App / RAG Platform --------- Co-authored-by: Sim Pi Agent <pi@sim.ai>
* feat(tables): support plain predicates in v2 queries * fix(tables): regenerate tool metadata * fix(tables): bound predicate validation
…ip to Chat (#6296) Sidebar: 11 separator groups become 5, with each module a collapsible folder that auto-opens on the active page. 61 always-visible rows drop to 16. Groups mirror the app's own nav (Chats/Workspace/Workflows) rather than inventing a taxonomy; Enterprise and Self-Hosting are hoisted out of Platform. Chrome: register the `hover-hover` variant, without which every @sim/emcn hover state silently compiled to nothing; restore the sidebar's Geist font stack; add 11 emcn tokens that were falling back to currentColor; adopt the named type scale; align row geometry, hover tokens and group labels with the app. Rename: mothership/ -> chat/ with redirects for the old URLs. Asset paths, the @mothership.sim.ai domain and the `mothership` log-trigger enum value are deliberately left alone -- they are CDN objects, a real domain, and a live product value. Also removes the page-type badge, drops the "Next" heading from the ToC, and lets FAQ rows open independently so expanding one no longer shifts the page.
…6293) * fix(files): stop a cached collab snapshot resurrecting blank lines A collaborative markdown file's cold-start seed can come from a cached Yjs snapshot (workspace_file_collab_state.doc_state) rather than a fresh markdown re-parse. The snapshot is a raw CRDT binary, so it preserves top-level empty paragraphs that parseMarkdownToDoc/stripEmptyParagraphs strips from every parse target. The static placeholder always re-parses (clean); a warm seed replays the snapshot verbatim, so a stray blank line appears once the doc settles — and only intermittently, since a stale/cold cache falls through to the clean re-parse. Enforce the same no-top-level-empty-paragraph invariant on the Yjs side: - normalize.ts: stripEmptyTopLevelParagraphs(doc) shared helper. - seed.ts: repair the cached snapshot on read (self-heals legacy snapshots, preserving CRDT client ids; no data migration). - persist.ts: normalize before caching so new snapshots are clean by construction. * refactor(collab-doc): make COLLAB_DOC_FIELD a single canonical constant converter.ts had a duplicate 'default' fragment-name constant; import the now-exported one from normalize.ts so the value TipTap's Collaboration binding depends on lives in exactly one place. Fold the back-to-front loop note into the helper's TSDoc.
…ss the panel (#6297) * fix(editor): restore caret alignment and the intended type scale across the panel Four distinct defects, all surfaced while testing the workflow editor. **Caret drift in the Start block's Description field.** Its overlay mirror was built differently from every sibling field: `overflow-hidden` + `truncate` and no scroll synchronisation, where the working fields use `overflow-x-auto` + `whitespace-pre` + `syncOverlayScroll`. Once the value passed the visible width the input scrolled and carried the caret with it while the overlay stayed pinned at the first character, so the gap grew as you typed. It now has the same plumbing as its siblings, on its own ref maps so it cannot collide with the value overlay. **Overlay mirrors left at 500 over 400 inputs.** #6291 dropped emcn Input and Textarea to the inherited weight, but the canvas files that mirror them were reverted from that PR, so 11 overlays kept a hardcoded `font-medium`. A mirror that renders heavier than the input beneath it misaligns by the weight delta on every character. All 11 realigned. **Input text tracking differently from its label.** The UA stylesheet resets form controls to `letter-spacing: normal`, so inside `.workspace-root` (0.02em) an input diverged from surrounding text — and from its own overlay — by 0.28px per character. emcn Input and Textarea now carry `[letter-spacing:inherit]`, which fixes every mirrored input at the source rather than per call site. **Weights and type sizes that changed meaning under #6241.** That PR deleted the tailwind remap of `font-medium` (440 light / 480 dark) without migrating the ~505 call sites written against it, so untouched code jumped to a stock 500. The panel's editor, toolbar, chat and connections surfaces are swept back to the inherited weight. The Chat header was also visibly taller than Toolbar and Editor purely because it used `text-[14px]` — font-size with no paired line-height — against otherwise byte-identical containers; it and the panel's two other arbitrary sizes now use named tokens. Also fixes five JSX conditionals in the workflow MCP settings page that had lost their braces, so `canManage && ()` rendered as literal text under the server detail tab. Verified: typecheck 0, biome clean, 18644/18645 vitest passing (the one failure is a missing `rg` binary and predates this branch). * fix(emcn): give chip text fields the same tracking as their mirrors An audit of the previous commit found the letter-spacing fix was incomplete: it landed on `Input`/`Textarea` but not on the chip family, so `ChipInput` and `ChipTextarea` kept the UA `letter-spacing: normal` while any overlay mirroring them inherited the ambient tracking. The MCP server form modal is a live instance — its shared `FormattedInput` layers a transparent `ChipInput` under a visible div, across the server URL and both header fields, whose values are long by nature. The caret separated from the text by roughly 0.28px per character. Fixed on `chipFieldTextClass` rather than the call site, so every chip field matches its mirror the way `Input`/`Textarea` already do. * fix(editor): restore the strong-text variant a class sweep welded together The font-weight sweep in 94c9f1f used a blanket sed, which turned [&_strong]:font-medium [&_strong]:text-[var(--text-primary)] into [&_strong]:[&_strong]:text-[var(--text-primary)] — a chained variant matching a <strong> inside a <strong>, so ordinary strong text in trigger setup instructions lost its color. The removed weight was also load-bearing rather than decorative. Preflight sets b/strong to font-weight: bolder, so against a 400 body a bare <strong> lands near 700; the class was holding it down to 500. Deleting it made that text heavier, the inverse of the sweep's intent — the same UA-default trap as <th>. Both variants are restored. Swept for the same damage: no chained [&…]:[&…] variants remain across apps/sim or packages, and this was the only variant-scoped weight the sed touched. Found independently by Greptile and Cursor Bugbot.
Bumps TABLE_LIMITS.MAX_COLUMNS_PER_TABLE from 50 to 1000. Every validation site (schema validation, add-column, bulk add, workflow output columns, and the boundary contract) already derives from this constant.
* fix(docs): stop the sidebar drifting when page content resizes The sidebar used fumadocs' `sticky` positioning, and a sticky box is bottom-limited by its containing block. #nd-docs-layout ends ~660px above the document bottom because the site footer is a sibling of the layout rather than a grid child, so across the whole footer the sidebar was pushed progressively upward. Any content-height change while the reader sat in that zone then moved it: expanding one FAQ row shifted the sidebar 16.8px at a fixed scroll offset, and collapsing it shifted it back. Pin the sidebar and its divider to the viewport instead. A fixed box ignores both the container's end and the document height, so neither the drift nor the jump can happen. The grid columns are explicit (`0px 300px 1fr 268px 0px`), so taking the placeholder out of flow leaves its track intact and the content column does not move. The footer is already opaque and now out-stacks both, so it slides over them at the end of the page. Measured with Playwright before and after: sidebar delta on expand/collapse 16.8px/-16.8px -> 0px/0px, content column left and width unchanged, and the sidebar holds top:92px at the page bottom on the docs, API-reference, academy and integrations layouts. Mobile is untouched (the rule is desktop-only). * refactor(docs): drop dead grid placement, move footer stacking to the component Review follow-ups. The divider's `grid-row`/`grid-column` stopped doing anything the moment it became `position: fixed` — a fixed box is out of grid layout entirely — so they and the comment explaining the grid span were describing positioning that no longer happens. Verified inert: the divider still computes to left 300px / width 1px / z-index 21 without them. The footer's stacking context also belongs on the footer, not in a global rule matching every desktop `footer` element, so it moves to the component as `relative z-[22]` with the reason in its TSDoc.
…ad (#6299) * fix(files): reserve image layout space so images stop reflowing on load A markdown image with no stored dimensions reserved zero vertical space until it downloaded, then snapped to its natural height and pushed content below it down (cumulative layout shift). Reserve the box up front from the image's intrinsic aspect ratio instead. Store intrinsic width/height as workspace_file metadata (not in the markdown — it stays clean ``), read it synchronously from the already-loaded file list to reserve a responsive aspect-ratio box on first render, and lazily backfill it once per image on first view via a write-gated, idempotent PATCH. The node view falls back to on-load measurement for the first-ever view and for external images. Images stay fluid (max-width:100%, height:auto). * fix(files): address review — reserve on stale memo, clear dims on content swap - onLoad guards on the memoized storedDimensions the render uses (not a fresh cache read), so a sibling's non-reactive backfill can't leave a view unreserved. - updateWorkspaceFileContent clears width/height when it swaps bytes, so stale dimensions can't be reserved for new content (and the null re-enables backfill). - Keep optimistically-cached dimensions when the PATCH fails (correct measurement; a 403/transient error shouldn't wipe sibling reservations). - Test imports the sibling via the absolute @/ path. * fix(files): re-derive image dimensions on content swap instead of clearing Clearing width/height to NULL on a content swap reopened the width IS NULL backfill path, so a late fire-and-forget PATCH for the previous image could write its stale size onto the new content. Instead, measure the new bytes' intrinsic dimensions server-side (image-size, headers only) and store those (or null for a non-image), so the row always matches the current content and a stale backfill can't apply. * fix(files): self-heal image dimensions from the browser instead of server-measuring Round-3 review: server-side image-size returns raw (non-EXIF) dimensions, and clearing dims on content swap reopened the stale-PATCH race for non-image or unmeasurable content. Move authority to the browser's own naturalWidth/Height (EXIF-correct): the node view reserves from it and reports on any mismatch, and updateWorkspaceFileDimensions overwrites (no width IS NULL gate) so stale values self-correct on the next view. Reverts the server-side measurement and the content-swap dimension touch entirely. * fix(files): clear image dimensions on content swap (completes self-heal) The self-heal rework left the old image's dimensions in the row after a content replacement, so the next view of the new bytes reserved a wrong-sized box before correcting. Clear width/height on the content-swap write so the row never describes stale content: the next view falls back to the baseline first-load reflow and the browser's measurement backfills the correct size. No server-side decode (EXIF-safe), and the client's overwrite-on-mismatch handles a late PATCH. * fix(files): guard dimension writes by content key so a stale PATCH can't persist Ties the dimensions write to the storage key the client measured. The key is regenerated on every content replacement, so an in-flight PATCH measured against superseded bytes is rejected at the DB (WHERE key = measured key) instead of persisting the old aspect ratio for new content. Closes the last stale-ordering window Greptile flagged — the write is now content-version-conditioned, not just corrected on the next render. * chore(files): fix stale route TSDoc and hoist a regex literal (cleanup pass) Post-review /cleanup: the dimensions route TSDoc still described backfill-once behavior (now overwrite-on-mismatch via the content-key CAS); the bare-pixel width regex is hoisted to module scope. No behavior change. * fix(files): reflect the content-version guard outcome in the dimensions response The route returned success:true even when updateWorkspaceFileDimensions matched 0 rows (the CAS rejected a write whose measured key no longer matches the row). Return success:<whether a row was written> and widen the contract response to { success: boolean }. Not an error path — the client's next measurement persists once its file list has the new key; this just stops the API claiming a persist that did not happen. * fix(files): reconcile the cache when a dimension write is content-version-rejected Previously the client discarded a success:false (CAS-rejected) response, leaving its optimistic patch — which is for superseded bytes — lingering in the file-list cache. On rejection, invalidate the list so the cache reconciles with the new content (whose real size persists on its next load). Deliberately NOT a retry: re-sending the old measurement under the new key would write the wrong size. A transport error / read-only 403 still keeps the optimistic value (it's the real displayed size). * docs(files): align stale dimension docs with the overwrite/self-heal behavior Cleanup audit: the ImageDimensionsSource/reportImageDimensions interface docs and one route log string still said backfill-once/no-op; the mechanism overwrites on mismatch to self-correct. Wording only, no behavior change.
|
Too many files changed for review (173 files, 100 file limit). Bypass the limit by tagging |
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
PR SummaryMedium Risk Overview Docs chrome changes pin the sidebar and divider with Product/API (in diff): Other items listed in the PR description (editor caret, collab blank lines, knowledge chunk scroll, column limit 1000, library page) are not in the attached diff. Reviewed by Cursor Bugbot for commit 5dbe95e. Configure here. |