Skip to content

feat(sidebar): show logged-in user's name in sidebar header#2

Closed
NagariaHussain wants to merge 76 commits into
developfrom
feat/sidebar-user-name
Closed

feat(sidebar): show logged-in user's name in sidebar header#2
NagariaHussain wants to merge 76 commits into
developfrom
feat/sidebar-user-name

Conversation

@NagariaHussain

Copy link
Copy Markdown
Owner

Why?

The sidebar header showed only the app name, with no indication of who is logged in. The LMS sidebar already surfaces the logged-in user's name in this spot, so we want parity in Wiki.

What?

Show the logged-in user's full name as the subtitle in the sidebar header, right below "Frappe Wiki".

How?

frappe-ui's SidebarHeader already supports a subtitle prop rendered below the title. The header object in Sidebar.vue is now a computed that sets subtitle: userStore.data?.full_name, so the name fills in reactively once the user resource loads.

🤖 Generated with Claude Code

NagariaHussain and others added 30 commits June 4, 2026 22:31
Use frappe-ui's usePageMeta (plugin was already registered but unused)
in each leaf route component so the tab title reflects what's open:
the page/draft title with its space name, the change request title,
or the static section name.

Titles live only in leaf components (not SpaceDetails) since each
usePageMeta watcher independently writes document.title and the last
one to fire wins — a parent title arriving late would clobber the
child's. Space names are read with getCachedDocumentResource because
createDocumentResource re-fetches on cache hit when auto is set.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…tles

feat(editor): dynamic browser tab titles
Adds a Wiki Setting (on by default) that converts PNG/JPEG images uploaded
in the editor to WebP server-side via Pillow, reducing page weight. Editor
uploads route through a dedicated `wiki.api.upload_wiki_asset` endpoint;
conversion is skipped (and the original kept) when the setting is off or the
image can't be decoded. Uploads now show an inline preview with a loading
state and swap to the optimized URL on success.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…e-conversion

feat(editor): auto-convert uploaded images to WebP
Add a PDF embed block to the wiki editor and public reader.

Editor (TipTap/Vue):
- New `pdfBlock` node + PdfBlockView (inline scrollable all-pages viewer,
  loading/error states) + PdfViewerModal (full-screen zoom/scroll).
- Toolbar button, `/pdf` slash command, and drag-drop, all routed through
  insertAndUploadPdf (optimistic loading; reuses upload_wiki_asset).
- Stored as `![filename](/files/x.pdf)`, disambiguated by extension; the
  image tokenizer yields to PDFs (as it already does to videos).

Public reader (Jinja + vanilla JS):
- markdown.py renders a `.wiki-pdf-embed` card (parallel to the video block);
  pdf-viewer.js hydrates an inline scrollable all-pages viewer + full-screen
  modal. Lazy via IntersectionObserver.
- pdfjs-dist vendored under public/js/vendor/pdfjs and served directly (no CDN).

Rendering uses PDF.js (vue-pdf-embed in the editor, pdfjs-dist on the public
side, pinned/matched at 4.10.38).

Also add get_asset_hash() jinja helper to cache-bust the public JS includes
(pdf-viewer/image-viewer/code-blocks) so structural changes don't break against
stale browser-cached scripts.
`get_asset_hash` is only ever called with hardcoded literal paths from our
own templates (layout.html), never with user input, and resolves under the
wiki app root. Add a targeted nosemgrep suppression so the Linters CI passes.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…beds

Opening any page containing a PDF embed in the editor froze the browser
tab. CPU profiling showed the main thread pegged in an infinite markdown
serialize/parse loop (normalizeMarkdown), not in PDF rendering — PDF.js
renders the file in ~130-380ms.

Root cause: `savedContent` (the "confirmed saved" baseline handed to the
editor for dirty detection) fell back to `editorContent`, which reflects
the draft store's `localContent`. That created a reactive cycle:

  watch(savedContent) -> emitContentReady -> reconcileEditorContent
    -> sets localContent -> editorContent recomputes -> savedContent
    recomputes -> watch fires again -> ...

The cycle only settles when the editor's serialized content equals the
normalized saved content. Plain prose reaches that fixed point in one
step, so it never looped. A PDF embed serializes to a form that differs
from the stored markdown, so the comparison never converged and the
watcher re-fired forever, each iteration running the expensive
parse+serialize round-trip seen in the profile.

Fix: `savedContent` now mirrors `editorContent` MINUS the `localContent`
branch, so the saved baseline never reflects the editor's unsaved local
snapshot and the watcher can't be re-triggered by the reconcile output it
feeds. This is also semantically correct — a "saved" baseline should not
include unsaved edits.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The earlier savedContent change (53c865a..e0a3899) did not fix the freeze;
this reverts it and fixes the actual root cause.

A page with two or more PDF embeds froze the editor tab. CPU profiling
showed an infinite markdown serialize/parse loop, and instrumenting the
live editor revealed why: the markdown round-trip was non-idempotent.
`PdfBlock.renderMarkdown` appended "\n\n", but the markdown serializer
already inserts a blank-line block separator between block nodes. The two
stack up, and the PreserveBlankLines extension then re-parses the extra
blanks into empty paragraphs, which add yet another separator on the next
cycle — so the gap between consecutive embeds grows without bound:

  ![a.pdf](/a.pdf)\n\n\n\n![b.pdf](/b.pdf)        (cycle 1)
  ![a.pdf](/a.pdf)\n\n\n\n\n\n![b.pdf](/b.pdf)    (cycle 2)  ...

`WikiDocumentPanel`'s content reconcile writes that normalized value back
into the store baseline that feeds the editor's `savedContent` watcher, so
a round-trip that never reaches a fixed point re-fires the watcher forever
and pegs the main thread.

Fix: drop the trailing "\n\n" from `PdfBlock.renderMarkdown`, exactly like
the image extension (which is idempotent for this reason). The round-trip
now converges in one step and the reconcile loop terminates. Verified on
the two-PDF demo page: editor mounts, both PDFs render, tab stays
responsive.

Note: video-block.js and iframe-block.js share the same "\n\n" pattern and
the same latent freeze for two consecutive embeds; left untouched here to
keep this change scoped to the reported PDF regression.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…embeds

video-block.js and iframe-block.js had the identical bug fixed for PDFs in
6dcaac7: their renderMarkdown appended "\n\n" on top of the serializer's
own block separator, so the markdown round-trip grew blank lines without
bound between two consecutive embeds and froze the editor in an infinite
reconcile loop.

Drop the trailing "\n\n" from both. Verified the round-trip now converges
in one step for two consecutive video and two consecutive iframe embeds.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
feat(editor): embed PDFs with inline scrollable viewer
Wiki Document.route is looked up on the main page-serving paths
(WikiDocumentRenderer.can_render, get_page_data, download_pdf) but had
no index, causing full table scans on every page view. Add search_index
so route lookups use a ref index instead.

Same class of fix as frappe#651 (Wiki Revision Item index).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add (change_request, status) on Wiki Merge Conflict and (wiki_space,
status) on Wiki Change Request via on_doctype_update hooks. These filter
combinations were doing full table scans:

- open/resolved conflict counts & listings filter by {change_request, status}
- _find_existing_draft / list_change_requests filter by {wiki_space, status}

modified timestamps bumped so the doctypes re-sync and the hooks run on
next migrate. Same class of fix as frappe#651.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
CR diff/merge and get_descendants_of range-scan the nested set via
WHERE lft >= ? AND rgt <= ?, previously a full table scan. Mirrors how
ERPNext indexes lft/rgt on its tree masters (Account, Item Group, etc.).

modified bumped so the doctype re-syncs on next migrate.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
perf: add missing DB indexes for hot lookups (closes frappe#651-class scans)
The public PDF viewer dynamically imports the vendored pdfjs bundle as an
ES module. It worked locally because the werkzeug dev server resolves .mjs
to text/javascript, but production nginx has no MIME mapping for .mjs and
serves it as application/octet-stream. Browsers enforce strict MIME checking
for module scripts and refuse to execute it, so the import failed
("Failed to fetch dynamically imported module ... pdf.min.mjs") and the
public cards never rendered.

Vendor the files as .js instead. .js is reliably served as text/javascript,
and dynamic import() keys off the MIME type rather than the extension, so the
files still load as ES modules. The internal
`GlobalWorkerOptions.workerSrc ||= "./pdf.worker.mjs"` default in the bundle
is never hit because pdf-viewer.js sets workerSrc explicitly.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
fix(pdf-embed): vendor pdfjs as .js so production serves it as JS
Configure per-space Read/Write access via existing Frappe Roles, enforced
across the Vue SPA, Desk, and the public portal by leaning on the framework
permission layer.

- Schema: new Wiki Space Role child doctype; roles table on Wiki Space;
  denormalized wiki_space link on Wiki Document; remove per-page is_private.
- Permissions: wiki/permissions.py helpers (can_read_space/can_write_space)
  + permission_query_conditions and has_permission hooks for Wiki Space,
  Wiki Document, Wiki Change Request.
- Content gates: check_space_access 404s unauthorized/guest hits across
  portal HTML, text/markdown, and PDF; wiki_space auto-stamped on update and
  re-stamped on reorder (live get_wiki_space fallback keeps gating correct).
- Change Requests: merge gated by per-space Write (_can_merge); Read-tier
  users can raise CRs, with a privileged bootstrap for fresh spaces.
- Migration: backfill_space_access patch denormalizes wiki_space and
  translates legacy is_private into Guest/All Read rows (raw-SQL read,
  has_column-guarded, idempotent).
- Frontend: SPA roles editor in Space Settings; Merge UI gated by
  get_space_capabilities; remove page-level Private toggle and lock icon.
- Search: post-filter hits by can_read_space so restricted titles/snippets
  don't leak.
- Reconcile existing tests to the new model; reconcile the spec to as-built.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Type-hint the `roles` arg of `update_space_roles` (missing-argument-type-hint).
- Annotate the privileged bootstrap `set_user` calls with `# nosemgrep`
  (frappe-setuser) — read access is already verified and the user is restored
  in `finally`.
- Annotate the already-guest-whitelisted `search` endpoint with `# nosemgrep`
  (guest-whitelisted-method), matching the existing convention in
  wiki_document.py; it now post-filters hits by read access.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…s, not set_user

`frappe.set_user` swaps the whole session (user, roles, cache) mid-request and
attributes the seed revision to Administrator. Match the first-party idiom
(Builder/Helpdesk: per-doc `insert(ignore_permissions=True)`) instead: thread
an `ignore_permissions` flag through `create_revision_from_live_tree` and have
`_bootstrap_main_revision` use it. The session stays intact and the bootstrap
revision keeps the real `created_by`. Removes the frappe-setuser Semgrep finding.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Add CLAUDE.md (Claude Code project guidance).
- Add specs/automatic_webp_image_optimization.md (as-built doc for the
  already-shipped WebP feature).
- Remove stale NOTES.md / TODO.md scratch files.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…n spec

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…roles editor

Add wiki/test_permissions.py covering the full read/write matrix (manager,
open, read-role, write-role, wrong-role, Guest/public), query-condition
filtering via get_list, the has_permission hooks, and the role-editor API —
replacing the temporary bench harness used during development.

Gate the SPA Access Control editor controls behind get_space_capabilities
.can_write so read-tier users see roles read-only instead of controls that
would 403 on save.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…-based role defaults

Refactor Space Settings into a Builder-style dialog with a vertical nav
(General / Permissions). Permissions renders roles as a CRM/LMS-styled
table with an inline Read/Write select, a hover trash action, and an
in-flow searchable role picker (select -> Add) that stays clickable
inside the reka-ui modal. Save sits below the table, disabled until
dirty, with an "Unsaved changes" badge next to the heading.

Seed sensible access defaults: new spaces (published by default) start
with Guest + All read; a patch makes existing empty spaces explicit from
is_published (published -> Guest + All read, unpublished -> All read),
skipping already-configured spaces. Empty roles still mean
open-to-logged-in as a backend fallback; managers bypass via _is_manager.

Also drop the sidebar resize handle's z-10 so the modal overlay covers it.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
frappe.get_roles() returns "Guest" for every user (anonymous and
logged-in), so a Guest Read row already makes a space readable by
everyone; only the anonymous Guest user lacks the "All" role. The paired
"All" row on published spaces was therefore redundant and inconsistent
with the existing backfill convention (Guest = public, All = login-only).

Map published -> Guest, unpublished -> All in both the seed patch and the
new-space UI default, and correct the patch docstring.

Verified: 27 permission tests pass; patch unit-tested (published->Guest,
unpublished->All, configured untouched, idempotent); migrate seeded 540
spaces with 0 empty / 0 published-but-login-only mismatches.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…PDATE

Replace the raw SQL bulk UPDATE in the backfill patch with frappe.qb on
the real wiki_space field. The is_private read stays raw SQL — it queries
a column removed from the DocType meta via a conditional aggregate, which
the query builder can't express cleanly (documented in the module).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…space-access-control

feat: role-based access control for Wiki Spaces
Plan for a ```mermaid fenced-block feature spanning both render stacks:
editor (TipTap node with code pane + live SVG preview) and the public
server-rendered reader (markdown.py fence interception + lazy client-side
mermaid render). Mirrors the PDF-embed precedent; client-side render,
securityLevel:'strict', vendored mermaid (.js not .mjs).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
(cherry picked from commit 3f4f7f9)
(cherry picked from commit 4ca6e07)
NagariaHussain and others added 27 commits June 19, 2026 12:56
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Bullet 5 of the change-request review revamp adds the notification plumbing.

- _notify_cr_owner: realtime ping (publish_realtime, after_commit) plus a
  best-effort Notification Log entry to the CR author. No-op when the actor
  is the author (self-serve approve & merge shouldn't notify yourself).
- Wired into approve / request_changes / reject and _finalize_merge (the
  single chokepoint for both merge paths).
- Frontend: global socket listener in App.vue toasts the author live; the
  Notification Log is the durable copy.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Bullet 6 of the change-request review revamp lets reviewers see the proposed
pages rendered exactly as they will publish, not just a markdown diff.

The live reader renders markdown server-side (wiki/markdown.py), so preview
parity comes from reusing that pipeline rather than a Vue component:

- get_cr_preview_context: runs the CR head-revision markdown through the same
  render_markdown_with_toc used by Wiki Document.get_web_context.
- ChangeRequestPreview page: tree sidebar (get_cr_tree) + rendered HTML pane;
  content styles lifted from the reader's main.css into shared wiki-rendered.css.
- Entry points: Preview button in the review header (any status) and a per-row
  Diff/Preview toggle that renders each page inline.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The editor banner's one-click Merge (managers, Draft/Changes Requested)
called merge_change_request directly, but Bullet 1 tightened merge to
require Approved — breaking one-click publish from the editor. Wire it to
walk the CR up the state machine in one click via a new store action
approveAndMergeChangeRequest() (submit -> approve -> merge, skipping
already-satisfied steps); on a merge-conflict ValidationError, route to
the review page's conflict-resolution UI.

Rewrite change-request-flow.spec.ts for the new flow: replace removed
request_review calls with submit_change_request, drive the Approve & Merge
confirm dialog, and add submit->assign->approve->merge (two-person),
request changes->revise->resubmit, and reject (terminal) scenarios.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The preview page's "Back to review" pushes a new history entry, while the
review page's Back used router.back() — so the two pinged between each
other and you could never leave the flow. The review page's Back now
navigates absolutely to the Change Requests list.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The outer p-4 plus frappe-ui Tabs' own px-5 inset gave the title, tab
labels, and list header three different left edges, and the ListView's
header butted straight against the tab bar with no gap. Drop the
conflicting p-4/gap-4 and pad each section to a consistent px-5, with
top/bottom padding on the panel for breathing room.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Clicking a page in the sidebar pushed a new history entry, so browser-back
walked back to the bare space landing ("select a page") and could
ping-pong between pages and the landing. Navigate with router.replace when
already inside the same space, so back returns to wherever the user entered
the space from.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Refine the change-request review experience:

- Inline Diff/Preview toggle: Preview now renders Current vs Proposed
  side-by-side via a read-only WikiContentViewer (same TipTap config as
  the editor) so syntax highlighting and custom blocks match the reader.
- Review actions: header primary is Approve -> then Merge; combined
  Approve & Merge moved into the three-dot menu.
- Assignees: CRM-style overlapping avatars in the list rows and review
  header. Fetch _assign via frappe.client.get_value (the document
  resource's frappe.client.get strips it).
- List: fix Assign button navigating to the CR (router-link anchor needs
  @click.stop.prevent, not just .stop).
- Reorder: show a structural before/after (path + sibling position)
  instead of an empty content diff; detect reorder by real position so
  order_index renumbering no longer flags unmoved pages; drop the
  structural root group from the breadcrumb.
- Navigation: Back buttons pop history (router.back) so the originating
  list tab/query is preserved and the review<->preview loop is gone;
  preview page-switching uses replace.

Tests: backend unit tests for reorder location/position and churn-skip;
e2e tests for assign-no-navigate, tab-preserving back, and the reorder
structural view.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…library

chore(deps): update @pierre/diffs to 1.2.11
The Wiki Spaces list now has an actions column with a View button on
published spaces that opens the public-facing reader (`/<route>`, served
at the site root outside the `/wiki` editor SPA) in a new tab. Uses
@click.stop.prevent so the click doesn't bubble into the row's
router-link navigation.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The View action sat far right with a wide gap from the route. Render it
inline in the Route cell instead, right after the route text, so it's
adjacent to what it opens.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Move View back into its own left-aligned column so the buttons form a
  straight column instead of jagging with each route's length; a wide
  last column keeps it near the route rather than at the far edge.
- Show a skeleton while the first page loads so the empty state no longer
  flashes on reload.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The review header primary is now Approve-only with Approve & Merge in the
three-dots menu, so specs that published a page by clicking a "Merge"
button (which used to substring-match "Approve & Merge") broke. Add a
publishChangeRequestFromReview helper that drives the new menu + confirm
flow, and use it across the public-reader specs.

API-merge specs (mobile-view, local-first-store) now approve before
merge since merge_change_request requires an Approved decision; also
replace the removed request_review call with submit_change_request.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ptor-driven

The Contributions tabs filtered on `userStore.user`, a property the user
store never exposes. The value was always `undefined`, so the inbox filtered
on `_assign LIKE %undefined%` (and "My Change Requests" on `owner = undefined`)
and showed nothing.

Rework the page around a single `tabDefs` descriptor list instead of three
hand-wired resources plus parallel options objects:

- `filters` is now a getter read at fetch time, so the session user can never
  be frozen in as `undefined` again.
- Lists are created and fetched lazily, only when a tab first becomes active
  (the resource `auto` flag is not reactive, so fetching is explicit). This
  drops the eager double-fetch on page load and the always-on `allInReview`
  query for non-managers.

Add an e2e regression test asserting a CR assigned to the current user shows
up under the "Assigned to me" tab.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…the space

Once the "Assigned to me"/"My Change Requests" filter was repaired, the My tab
finally returned rows — exposing a latent bug: a Draft/Changes-Requested row
routes to the space editor via `row.wiki_space`, but only `wiki_space.space_name`
was selected, so `spaceId` was undefined and vue-router threw "Missing required
param". Select the `wiki_space` link id alongside the display name.

Add an e2e regression test asserting the My tab renders a draft row linking to
its space without a router param error.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Narrow Author and Status, give Space more room, and move "Submitted" to the
end as a compact clock-marked date column: drop the in-cell time (the width
hog) to a date only, drop the header text in favour of the icon, and surface
the full timestamp on hover.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…itor styles

The preview rendered server HTML via v-html, so it had no syntax highlighting
and didn't match the editor. Render it through the same read-only
WikiContentViewer (lowlight, callouts, tables) the editor/diff use:

- expose the raw markdown `content` from get_cr_preview_context
- the content/code/highlight CSS lived in WikiEditor.vue's lazy chunk, so it
  was absent on the preview page; extract it to a global wiki-editor-content.css
  imported in main.js, and move the editing-surface box (border + min-height +
  padding) behind an `.is-editable` modifier the editor opts into
- hide the code-block language picker when the editor is read-only
- make the preview full-bleed and drop the redundant page title (it's in the
  sidebar)

Extend the preview e2e test to assert lowlight highlighting renders and the
language picker does not leak into the read-only view.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…-revamp

feat: change request review flow revamp
Diagrams rendered with Mermaid's stock light/dark palette, which clashed
with the wiki's look. Replace the "default"/"dark" theme switch with a
single `base` theme whose themeVariables are resolved live from the
Frappe UI gray/surface/ink tokens (read as hex via getComputedStyle).

Because the tokens flip with `<html data-theme>`, one mapping renders
correctly in both modes — no more separate dark/default branch. The
config lives in one place (wikiMermaidThemeConfig in the shared loader)
and is reused by the public renderer and the editor preview, so the
in-editor diagram matches the published page.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
# Conflicts:
#	frontend/src/pages/ContributionReview.vue
#	frontend/src/pages/SpaceDetails.vue
The change-request preview (full page + split-pane) renders markdown
through WikiContentViewer, which lacked the MermaidBlock extension — so
mermaid fences fell through to a plain code block and never rendered.

Register MermaidBlock in the viewer and give MermaidBlockView a
read-only branch: when the editor isn't editable it drops the split-pane
editing chrome and shows only the rendered diagram as a centered figure,
matching the published page.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
feat: Mermaid diagram editing & embedding
Surface the logged-in user's full name as the sidebar header subtitle,
matching the placement used in the LMS sidebar. Uses the existing
`subtitle` prop on frappe-ui's SidebarHeader.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jun 20, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 3aa34407-1a98-4f2d-89b0-31a748ef0d01

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/sidebar-user-name

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@NagariaHussain

Copy link
Copy Markdown
Owner Author

Reopening against frappe/wiki upstream.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants