Skip to content

[WIKI-400] feat: page navigation pane#7206

Merged
sriramveeraghanta merged 27 commits intopreviewfrom
feat/page-navigation-pane
Jul 2, 2025
Merged

[WIKI-400] feat: page navigation pane#7206
sriramveeraghanta merged 27 commits intopreviewfrom
feat/page-navigation-pane

Conversation

@aaryan610
Copy link
Member

@aaryan610 aaryan610 commented Jun 12, 2025

Description

This PR includes the implementation of a new navigation pane for pages consisting of a wide range of information of the current page, including-

  1. Outline- Table of content
  2. Info- Document info and version history
  3. Assets- List of all the assets(Images, file attachments, work item embeds, sub-pages and more to come)
  4. New download feature for images.

Type of Change

  • Feature (non-breaking change which adds functionality)

Media

Screen.Recording.2025-06-16.at.19.54.46.mov

Fixes

#7169

Summary by CodeRabbit

  • New Features

    • Introduced a page navigation pane with tabs for Outline, Info, and Assets, accessible via the editor interface.
    • Added tabbed navigation with localized labels and empty states, supporting multiple languages.
    • Implemented document statistics (word, character, paragraph count, read time) and version history within the Info tab.
    • Assets tab displays a list of document assets with download options and empty state messaging.
    • Enhanced editor toolbar and body with controls to open/close the navigation pane, including floating and accessible buttons.
    • Added a read-only editor API and hooks to support asset tracking and document info updates.
    • Smooth scrolling enabled across all interfaces for improved navigation experience.
  • Improvements

    • Editor asset management is now observable, with real-time updates to asset lists as files are added or removed.
    • Refined document editor API to support new asset and navigation features.
    • Updated UI to provide a more streamlined version history experience.
    • Consolidated editor helper methods for better modularity and maintainability.
    • Simplified version overlay logic by controlling state via URL query parameters.
  • Bug Fixes

    • Improved accessibility and internationalization for navigation pane controls and tab labels.
  • Documentation

    • Expanded localization files with new keys and translations for navigation pane features in all supported languages.
  • Style

    • Unified and enhanced component styling for tabs, buttons, and navigation pane layout.
    • Added smooth scroll behavior to global styles for a consistent user experience.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jun 12, 2025

Walkthrough

This update introduces a comprehensive "Page Navigation Pane" feature across the editor and web application. It adds a multi-tabbed sidebar for pages, enabling users to browse an outline, view document info and version history, and manage assets. Supporting changes include new MobX stores for editor state, asset tracking, new types, utility functions, and extensive localization updates for the navigation pane UI.

Changes

Files/Groups Change Summary
packages/editor/src/core/hooks/use-editor.ts, use-collaborative-editor.ts, editor-ref.ts, core/types/editor.ts, core/types/hook.ts, core/types/asset.ts, core/types/index.ts, core/extensions/utility.ts, core/extensions/custom-image/utils.ts, core/extensions/custom-image/components/block.tsx, core/plugins/file/delete.ts, core/plugins/file/restore.ts, core/helpers/assets.ts, core/helpers/editor-ref.ts, ce/constants/assets.ts, ce/constants/extensions.ts, ce/types/asset.ts, ce/types/storage.ts, core/types/storage.ts, index.ts Refactor and extend editor API, asset management, and types; add asset tracking, new extension points, utility functions, and update exports.
web/core/store/pages/base-page.ts, web/core/store/pages/page-editor-info.ts Refactor page state management: remove direct editorRef, introduce PageEditorInstance MobX store for editor ref and assets list.
web/core/components/pages/navigation-pane/ (all new files), web/ce/components/pages/navigation-pane/ Add navigation pane components: root, tabs, tab panels (outline, info, assets), MobX observers, and supporting types.
web/core/components/pages/editor/toolbar/root.tsx, editor-body.tsx, summary/content-browser.tsx, summary/heading-components.tsx, toolbar/options-dropdown.tsx Integrate navigation pane controls, update toolbar and outline, enhance content browser with empty state and styling improvements.
web/core/components/pages/editor/page-root.tsx, web/core/components/pages/version/root.tsx, main-content.tsx, editor.tsx, index.ts Refactor page and version overlay logic: remove sidebar, simplify version handling, integrate navigation pane, update props and structure.
web/core/components/pages/header/actions.tsx Remove usage of PageInfoPopover (now deleted).
web/core/components/pages/editor/toolbar/index.ts, toolbar/info-popover.tsx Remove info popover export and component.
packages/utils/src/editor.ts Add getEditorAssetDownloadSrc utility for asset downloads.
packages/i18n/src/locales/*/translations.json Add localization for navigation pane UI in all supported languages.
admin/styles/globals.css, web/styles/globals.css, space/styles/globals.css Add scroll-behavior: smooth; for global smooth scrolling.
web/core/hooks/use-query-params.ts Memoize updateQueryParams with useCallback.

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant PageRoot
  participant NavigationPane
  participant EditorInstance
  participant MobXStore

  User->>PageRoot: Opens page
  PageRoot->>NavigationPane: Renders with props (open/close, page, version handlers)
  NavigationPane->>MobXStore: Observes page.editor.editorRef, assetsList
  User->>NavigationPane: Clicks tab (Outline/Info/Assets)
  NavigationPane->>EditorInstance: Reads headings, document info, assets via editorRef
  EditorInstance->>MobXStore: Updates assetsList on asset change
  MobXStore->>NavigationPane: Triggers UI update (outline, info, assets)
  User->>NavigationPane: Clicks asset download
  NavigationPane->>EditorInstance: Resolves asset URL, triggers download
Loading

Possibly related PRs

  • makeplane/plane#7246: Both PRs enhance the collaborative editor with new event callbacks, focusing on different handlers (onAssetChange vs. onChange).
  • makeplane/plane#6946: Both PRs refactor how the editor reference is stored in the page instance, moving towards MobX-based sub-stores and updating component access patterns.

Suggested labels

pages, ready to merge

Suggested reviewers

  • anmolsinghbhatia
  • prateekshourya29

Poem

In the warren, a sidebar grew,
With tabs for assets, outline too.
Info, versions, all in line,
Navigation pane—how divine!
Rabbits hop through pages bright,
Smoothly scrolling, left and right.
🐇✨ Code and carrots, pure delight!


📜 Recent review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2f6b42d and b5f41eb.

📒 Files selected for processing (1)
  • web/ce/components/pages/navigation-pane/tab-panels/empty-states/assets.tsx (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • web/ce/components/pages/navigation-pane/tab-panels/empty-states/assets.tsx
✨ Finishing Touches
  • 📝 Generate Docstrings

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
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@makeplane
Copy link

makeplane bot commented Jun 12, 2025

Pull Request Linked with Plane Work Items

Comment Automatically Generated by Plane

@aaryan610 aaryan610 marked this pull request as ready for review June 13, 2025 10:56
@Palanikannan1437 Palanikannan1437 marked this pull request as draft June 13, 2025 11:01
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 15

🔭 Outside diff range comments (1)
web/core/components/pages/version/main-content.tsx (1)

31-38: ⚠️ Potential issue

SWR cache key is not unique per page – risk of cross-page data bleed

Using only "PAGE_VERSION_${activeVersion}" ignores pageId, so visiting two different pages that happen to share a version UUID will share the same cache entry.

-  pageId && activeVersion ? `PAGE_VERSION_${activeVersion}` : null,
-  pageId && activeVersion ? () => fetchVersionDetails(pageId, activeVersion) : null
+  pageId && activeVersion ? ["PAGE_VERSION", pageId, activeVersion] : null,
+  pageId && activeVersion ? () => fetchVersionDetails(pageId, activeVersion) : null

SWR stringifies array keys, guaranteeing uniqueness and preserving the existing cache-invalidation behavior.

🧹 Nitpick comments (24)
packages/editor/src/ce/constants/extensions.ts (1)

1-1: Add documentation to the placeholder enum

The exported ADDITIONAL_EXTENSIONS enum is currently empty—consider adding a comment describing its intended use or deferring its introduction until it contains members to avoid confusion.

web/helpers/editor.helper.ts (1)

25-28: Doc-string copy-paste

The JSDoc still says “generate the file source using assetId”. Clarify that this variant returns a download URL to avoid confusion when scanning the file.

packages/editor/src/ce/constants/assets.ts (1)

6-6: Empty placeholder constant

ADDITIONAL_ASSETS_META_DATA_RECORD is currently an empty object. If this is intentional scaffolding, add a TODO comment describing how/when it will be populated to avoid it being mistaken for dead code later.

web/core/components/pages/navigation-pane/tabs-list.tsx (2)

25-31: Animation math ties to list length

left and width are derived from ORDERED_PAGE_NAVIGATION_TABS_LIST.length.
If tabs are ever conditionally hidden or added at runtime, the indicator will be mis-aligned.

Consider computing positions from the actual rendered tab count (React.Children.count) or from the element’s offset width for robustness.


15-23: Minor: provide index in map for clarity

Tab supplies selectedIndex but the individual button doesn’t know its own index – using the map’s index can be helpful for debugging or aria attributes.

-{ORDERED_PAGE_NAVIGATION_TABS_LIST.map((tab) => (
+{ORDERED_PAGE_NAVIGATION_TABS_LIST.map((tab, idx) => (
   <Tab
     key={tab.key}
     type="button"
     className="relative z-[1] flex-1 py-1.5 text-sm font-semibold outline-none"
   >
     {t(tab.i18n_label)}
   </Tab>
 ))}
web/core/components/pages/navigation-pane/tab-panels/outline.tsx (1)

24-36: Memoise the Empty-State element & localise the alt text.

  1. EmptyState is recreated on every render; wrap it in useMemo to avoid useless re-allocations.
  2. The hard-coded alt string bypasses i18n. Expose it via t(...) so screen-reader users get a translated description.
+  const EmptyState = useMemo(
+    () => (
       ...
-        <Image src={resolvedPath} width={160} height={160} alt="An image depicting the outline of a page" />
+        <Image
+          src={resolvedPath}
+          width={160}
+          height={160}
+          alt={t("page_navigation_pane.tabs.outline.empty_state.image_alt")}
+        />
       ...
-  );
+    ),
+    [resolvedPath, t]
+  );
web/core/components/pages/editor/summary/heading-components.tsx (1)

13-29: Expose full heading text via title to improve accessibility.

Because the label is truncated with truncate, users can’t see the full heading unless they click it. Adding title={marking.text} keeps the UI unchanged while providing the full text on hover & for assistive tech.

-  <button type="button" onClick={onClick} className={cn(COMMON_CLASSNAME, "text-sm pl-1")}>
+  <button
+    type="button"
+    onClick={onClick}
+    className={cn(COMMON_CLASSNAME, "text-sm pl-1")}
+    title={marking.text}
+  >

Apply the same to OutlineHeading2 and OutlineHeading3.

web/core/components/pages/navigation-pane/tab-panels/info/document-info.tsx (2)

29-36: Guard against missing editorRef.

editorRef is optional (?. is used), but if it’s undefined, the component still subscribes & shows zeroed stats forever.
Consider an early-return fallback to avoid misleading information:

if (!editorRef) {
  return null; // or a dedicated “unavailable” state
}

38-42: secondsToReadableTime ignores i18n & plural rules.

Formatting "60s" vs "1m" is language-dependent and may need pluralisation.
Expose it through the translation layer or at least allow overriding the units.

web/core/components/pages/navigation-pane/tab-panels/root.tsx (1)

24-35: All tab panels stay mounted – could waste resources.

@headlessui/react will keep every <Tab.Panel> in the DOM unless you add unmount.
Panels like “info” subscribe to editor updates and can run expensive observers. Mounting only the active tab avoids unnecessary work.

-        <Tab.Panel
+        <Tab.Panel
+          unmount={true}
web/core/components/pages/editor/summary/content-browser.tsx (1)

39-44: Micro-perf: move HeadingComponent mapping out of render

HeadingComponent is recreated on every render. Memoising (or defining it outside the component) avoids needless allocations and keeps referential equality stable.

-const HeadingComponent: {
-  [key: number]: React.FC<THeadingComponentProps>;
-} = {
+// move this *above* the component definition
+export const HEADING_COMPONENT: {
+  [key: number]: React.FC<THeadingComponentProps>;
+} = {
 };
 
 // inside the component
-const HeadingComponent = HEADING_COMPONENT;
packages/editor/src/core/hooks/use-read-only-editor.ts (1)

75-75: Stabilise imperative handle with dependencies

useImperativeHandle is called without a deps array, so forwardedRef.current is reassigned on every render even when editor is unchanged.
Providing [editor, provider] keeps the same object reference unless something relevant really changed.

-useImperativeHandle(forwardedRef, () => getEditorRefHelpers({ editor, provider }));
+useImperativeHandle(
+  forwardedRef,
+  () => getEditorRefHelpers({ editor, provider }),
+  [editor, provider]
+);
web/core/components/pages/navigation-pane/tab-panels/info/actors-info.tsx (1)

30-66: Duplication between “edited by” and “created by” blocks – extract a small presentational component

The two sections share identical structure. Extracting something like <UserMeta label="Edited by" userId={...} date={...} /> will cut the duplication, simplify maintenance, and reduce future divergence in styling.

web/ce/components/pages/navigation-pane/index.ts (1)

1-22: Use as const to retain literal types & avoid widening

Adding as const to PAGE_NAVIGATION_PANE_TABS_LIST preserves literal string unions for callers and eliminates the need for repetitive key properties.

> = {
   outline: {
     key: "outline",
     i18n_label: "page_navigation_pane.tabs.outline.label",
   },
   ...
-};
+} as const;

This also allows ORDERED_PAGE_NAVIGATION_TABS_LIST to derive types without additional assertions.

web/core/components/pages/editor/toolbar/root.tsx (2)

54-60: Add aria-label & translation to the visible navigation-pane toggle button

The floating button (lines 69-76) is accessible, but the primary toolbar button is missing an aria-label, making it invisible to screen-reader users and inconsistent with the hidden-toolbar variant.

-<button
+<button
   type="button"
   className="flex-shrink-0 size-6 grid place-items-center rounded text-custom-text-200 hover:text-custom-text-100 hover:bg-custom-background-80 transition-colors"
   onClick={handleOpenNavigationPane}
+  aria-label={t("page_navigation_pane.open_button")}
 >

53-77: DRY: duplicate toggle-button markup appears twice

The two identical button blocks (inside toolbar & floating) could be abstracted into a small <NavigationPaneToggle /> component to prevent drift and simplify future style updates.

web/core/components/pages/navigation-pane/tab-panels/info/version-history.tsx (1)

85-89: Consider deterministic ordering of versions

fetchAllVersions may return unsorted data. Sorting (e.g. by last_saved_at descending) guarantees a stable UI and prevents accidental re-ordering when the backend changes its default.

const { data: versionsList } = useSWR(
  id ? `PAGE_VERSIONS_LIST_${id}` : null,
  id ? () => versionHistory.fetchAllVersions(id).then(v => v?.sort((a,b) => Date.parse(b.last_saved_at) - Date.parse(a.last_saved_at))) : null,
);
web/core/components/pages/navigation-pane/root.tsx (1)

48-56: Use router.replace + shallow routing to avoid full page navigations on tab switch

Tab changes only mutate query parameters. router.push triggers a full navigation, which is heavier and resets scroll position. Replacing in place keeps history lean and improves UX.

-      const updatedRoute = updateQueryParams({
-        paramsToAdd: { [PAGE_NAVIGATION_PANE_TABS_QUERY_PARAM]: updatedTab },
-      });
-      router.push(updatedRoute);
+      router.replace(
+        updateQueryParams({ paramsToAdd: { [PAGE_NAVIGATION_PANE_TABS_QUERY_PARAM]: updatedTab } }),
+        { scroll: false }
+      );
web/core/components/pages/navigation-pane/tab-panels/assets.tsx (1)

101-110: Effect dependency should include page or editorRef stable reference

If page.editorRef changes, the cleanup of the previous subscription is skipped because the dependency array only tracks editorRef reference identity. If page is re-created elsewhere, explicitly include it to avoid leaks.

-}, [editorRef]);
+}, [page, editorRef]);
web/core/components/pages/version/root.tsx (1)

50-51: Avoid layout coupling with a magic width

The overlay always reserves 100% - 294px, even when the navigation pane is closed, creating dead space and complicating responsive layouts.
Compute the width conditionally or derive it from a CSS variable controlled by the nav-pane state.

web/core/components/pages/editor/page-root.tsx (2)

103-108: Memoise derived flag

isValidNavigationPaneTab recalculates on every render.
Wrap it in useMemo with navigationPaneQueryParam as dep to avoid useless renders once the editor grows heavier.


110-114: Use router.replace to prevent history spam

Opening the navigation pane just toggles a UI element; adding a new entry to browser history on every toggle (router.push) clutters the back-stack.
router.replace (or { scroll:false }) keeps the URL in sync without polluting history.

packages/editor/src/core/types/editor.ts (1)

108-109: Consistent casing for markdown helper

The method is getMarkDown, but the underlying storage helper is getMarkdown(). Align the casing (getMarkdown) to avoid confusion.

packages/editor/src/core/hooks/use-editor.ts (1)

220-227: Throttle expensive document-info computations

onDocumentInfoChange recomputes counts on every transaction, traversing the doc each time.
Wrap the handler in a throttle/debounce (e.g. 250 ms) to avoid UI jank on rapid typing.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6fe0415 and 553aa62.

📒 Files selected for processing (40)
  • packages/editor/src/ce/constants/assets.ts (1 hunks)
  • packages/editor/src/ce/constants/extensions.ts (1 hunks)
  • packages/editor/src/ce/types/storage.ts (2 hunks)
  • packages/editor/src/core/extensions/custom-image/components/image-block.tsx (2 hunks)
  • packages/editor/src/core/helpers/assets.ts (1 hunks)
  • packages/editor/src/core/helpers/editor-ref.ts (1 hunks)
  • packages/editor/src/core/hooks/use-editor.ts (4 hunks)
  • packages/editor/src/core/hooks/use-read-only-editor.ts (3 hunks)
  • packages/editor/src/core/plugins/drag-handle.ts (3 hunks)
  • packages/editor/src/core/types/editor.ts (2 hunks)
  • web/ce/components/pages/navigation-pane/index.ts (1 hunks)
  • web/ce/components/pages/navigation-pane/tab-panels/root.tsx (1 hunks)
  • web/core/components/pages/editor/editor-body.tsx (5 hunks)
  • web/core/components/pages/editor/page-root.tsx (4 hunks)
  • web/core/components/pages/editor/summary/content-browser.tsx (3 hunks)
  • web/core/components/pages/editor/summary/heading-components.tsx (1 hunks)
  • web/core/components/pages/editor/toolbar/index.ts (0 hunks)
  • web/core/components/pages/editor/toolbar/info-popover.tsx (0 hunks)
  • web/core/components/pages/editor/toolbar/root.tsx (3 hunks)
  • web/core/components/pages/header/actions.tsx (1 hunks)
  • web/core/components/pages/navigation-pane/index.ts (1 hunks)
  • web/core/components/pages/navigation-pane/root.tsx (1 hunks)
  • web/core/components/pages/navigation-pane/tab-panels/assets.tsx (1 hunks)
  • web/core/components/pages/navigation-pane/tab-panels/info/actors-info.tsx (1 hunks)
  • web/core/components/pages/navigation-pane/tab-panels/info/document-info.tsx (1 hunks)
  • web/core/components/pages/navigation-pane/tab-panels/info/root.tsx (1 hunks)
  • web/core/components/pages/navigation-pane/tab-panels/info/version-history.tsx (1 hunks)
  • web/core/components/pages/navigation-pane/tab-panels/outline.tsx (1 hunks)
  • web/core/components/pages/navigation-pane/tab-panels/root.tsx (1 hunks)
  • web/core/components/pages/navigation-pane/tabs-list.tsx (1 hunks)
  • web/core/components/pages/version/editor.tsx (3 hunks)
  • web/core/components/pages/version/index.ts (0 hunks)
  • web/core/components/pages/version/main-content.tsx (5 hunks)
  • web/core/components/pages/version/root.tsx (1 hunks)
  • web/core/components/pages/version/sidebar-list-item.tsx (0 hunks)
  • web/core/components/pages/version/sidebar-list.tsx (0 hunks)
  • web/core/components/pages/version/sidebar-root.tsx (0 hunks)
  • web/core/hooks/use-query-params.ts (2 hunks)
  • web/helpers/editor.helper.ts (1 hunks)
  • web/styles/globals.css (1 hunks)
💤 Files with no reviewable changes (6)
  • web/core/components/pages/editor/toolbar/index.ts
  • web/core/components/pages/version/index.ts
  • web/core/components/pages/version/sidebar-list.tsx
  • web/core/components/pages/version/sidebar-list-item.tsx
  • web/core/components/pages/version/sidebar-root.tsx
  • web/core/components/pages/editor/toolbar/info-popover.tsx
🧰 Additional context used
🧬 Code Graph Analysis (17)
web/ce/components/pages/navigation-pane/tab-panels/root.tsx (2)
web/ce/components/pages/navigation-pane/index.ts (1)
  • TPageNavigationPaneTab (1-1)
web/core/store/pages/base-page.ts (1)
  • TPageInstance (67-70)
web/helpers/editor.helper.ts (2)
apiserver/plane/settings/storage.py (1)
  • url (15-16)
web/core/store/router.store.ts (2)
  • projectId (85-87)
  • workspaceSlug (69-71)
web/core/components/pages/navigation-pane/tabs-list.tsx (3)
packages/i18n/src/hooks/use-translation.ts (1)
  • useTranslation (23-35)
web/ce/components/pages/navigation-pane/index.ts (1)
  • ORDERED_PAGE_NAVIGATION_TABS_LIST (24-31)
packages/i18n/src/store/index.ts (1)
  • t (211-232)
packages/editor/src/ce/constants/assets.ts (1)
packages/editor/src/core/helpers/assets.ts (1)
  • TAssetMetaDataRecord (12-12)
packages/editor/src/core/hooks/use-read-only-editor.ts (1)
packages/editor/src/core/helpers/editor-ref.ts (1)
  • getEditorRefHelpers (20-57)
web/core/components/pages/navigation-pane/tab-panels/outline.tsx (4)
web/core/store/pages/base-page.ts (1)
  • TPageInstance (67-70)
web/core/hooks/use-resolved-asset-path.tsx (1)
  • useResolvedAssetPath (10-26)
packages/i18n/src/hooks/use-translation.ts (1)
  • useTranslation (23-35)
web/core/components/pages/editor/summary/content-browser.tsx (1)
  • PageContentBrowser (16-81)
web/core/components/pages/editor/editor-body.tsx (2)
packages/i18n/src/hooks/use-translation.ts (1)
  • useTranslation (23-35)
web/core/components/pages/editor/summary/content-browser.tsx (1)
  • PageContentBrowser (16-81)
web/core/components/pages/navigation-pane/index.ts (1)
web/ce/components/pages/navigation-pane/index.ts (1)
  • ORDERED_PAGE_NAVIGATION_TABS_LIST (24-31)
web/core/components/pages/version/main-content.tsx (1)
web/helpers/date-time.helper.ts (1)
  • renderFormattedTime (79-94)
web/core/components/pages/editor/summary/heading-components.tsx (1)
packages/editor/src/core/extensions/headings-list.ts (1)
  • IMarking (6-11)
web/core/components/pages/version/root.tsx (3)
web/core/components/pages/version/editor.tsx (1)
  • TVersionEditorProps (17-20)
web/core/hooks/use-query-params.ts (1)
  • useQueryParams (8-37)
web/core/components/pages/navigation-pane/index.ts (2)
  • PAGE_NAVIGATION_PANE_VERSION_QUERY_PARAM (9-9)
  • PAGE_NAVIGATION_PANE_WIDTH (6-6)
web/core/components/pages/navigation-pane/tab-panels/info/version-history.tsx (7)
web/core/store/pages/base-page.ts (1)
  • TPageInstance (67-70)
web/core/components/pages/editor/page-root.tsx (1)
  • TPageRootHandlers (32-39)
packages/i18n/src/hooks/use-translation.ts (1)
  • useTranslation (23-35)
web/helpers/date-time.helper.ts (1)
  • renderFormattedTime (79-94)
packages/ui/src/avatar/avatar.tsx (1)
  • Avatar (116-169)
web/core/components/pages/navigation-pane/index.ts (1)
  • PAGE_NAVIGATION_PANE_VERSION_QUERY_PARAM (9-9)
web/core/hooks/use-query-params.ts (1)
  • useQueryParams (8-37)
web/core/components/pages/navigation-pane/tab-panels/assets.tsx (7)
web/core/store/pages/base-page.ts (1)
  • TPageInstance (67-70)
packages/editor/src/core/types/editor.ts (1)
  • TEditorAsset (82-89)
packages/i18n/src/hooks/use-translation.ts (1)
  • useTranslation (23-35)
web/core/store/router.store.ts (1)
  • workspaceSlug (69-71)
web/helpers/editor.helper.ts (2)
  • getEditorAssetSrc (14-23)
  • getEditorAssetDownloadSrc (29-38)
packages/utils/src/attachment.ts (1)
  • convertBytesToSize (22-32)
web/core/hooks/use-resolved-asset-path.tsx (1)
  • useResolvedAssetPath (10-26)
packages/editor/src/core/helpers/assets.ts (3)
packages/editor/src/core/types/editor.ts (1)
  • TEditorAsset (82-89)
packages/editor/src/core/extensions/custom-image/components/image-block.tsx (1)
  • getImageBlockId (41-41)
packages/editor/src/ce/constants/assets.ts (1)
  • ADDITIONAL_ASSETS_META_DATA_RECORD (6-6)
web/core/components/pages/editor/toolbar/root.tsx (4)
web/core/store/pages/base-page.ts (1)
  • TPageInstance (67-70)
packages/i18n/src/hooks/use-translation.ts (1)
  • useTranslation (23-35)
web/core/components/pages/editor/toolbar/toolbar.tsx (1)
  • PageToolbar (66-164)
web/ce/components/pages/header/collaborators-list.tsx (1)
  • PageCollaboratorsList (10-10)
packages/editor/src/core/types/editor.ts (1)
packages/editor/src/core/extensions/headings-list.ts (1)
  • IMarking (6-11)
packages/editor/src/core/hooks/use-editor.ts (5)
packages/editor/src/core/helpers/editor-ref.ts (1)
  • getEditorRefHelpers (20-57)
packages/editor/src/core/helpers/get-extension-storage.ts (1)
  • getExtensionStorage (5-8)
packages/editor/src/core/helpers/assets.ts (1)
  • getAllEditorAssets (39-54)
packages/editor/src/core/helpers/common.ts (1)
  • getParagraphCount (92-99)
packages/editor/src/core/helpers/insert-content-at-cursor-position.ts (1)
  • insertContentAtSavedSelection (3-22)
⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: Analyze (javascript)
🔇 Additional comments (19)
web/styles/globals.css (1)

500-500: Enable smooth scrolling globally

Adding scroll-behavior: smooth at the global selector aligns with the new navigation pane's scroll-to-section feature.

web/core/components/pages/header/actions.tsx (1)

5-5: Imported PageOptionsDropdown for new options menu

The PageOptionsDropdown replaces the removed PageInfoPopover to surface page actions—import path and usage look correct.

packages/editor/src/ce/types/storage.ts (1)

1-1: Integrate character count into extension storage

The CharacterCountStorage is now mapped under CORE_EXTENSIONS.CHARACTER_COUNT, matching the new document info API. Imports and type mapping appear correct.

Also applies to: 19-19

web/helpers/editor.helper.ts (1)

25-38: Avoid duplicating logic & tighten return type

getEditorAssetDownloadSrc repeats almost the exact branch logic of getEditorAssetSrc. Consider extracting the common URL prefix builder or passing a boolean flag indicating “download” to a single helper – this prevents two functions from silently diverging.

In addition, the function is typed to return string | undefined but always returns a string ("" at worst). Either change the initial value to undefined or narrow the return type to string for consistency with actual behavior.

-export const getEditorAssetDownloadSrc = (args: TEditorSrcArgs): string | undefined => {
+export const getEditorAssetDownloadSrc = (args: TEditorSrcArgs): string => {
   const { assetId, projectId, workspaceSlug } = args;
-  let url: string | undefined = "";
+  let url = "";

[ suggest_essential_refactor ]

packages/editor/src/ce/constants/assets.ts (1)

1-7: Potential incorrect import alias

import { TAssetMetaDataRecord } from "@/helpers/assets";

Inside packages/editor, the alias @/ usually resolves to packages/editor/src.
The actual file lives at core/helpers/assets.ts, so the correct path should likely be:

import { TAssetMetaDataRecord } from "@/core/helpers/assets";

Please verify the ts-config path mapping; otherwise this will break type-checking and builds.

web/core/components/pages/navigation-pane/tab-panels/outline.tsx (1)

18-18: editorRef might not exist on TPageInstance.

editorRef is destructured directly from page, yet the snippet that defines TPageInstance doesn’t list this property.
If the type wasn’t extended elsewhere, this will raise a TypeScript error.

Please confirm that TPageInstance has been augmented (e.g., via declaration merging) to include editorRef, or update the prop typing accordingly.

web/core/components/pages/editor/summary/heading-components.tsx (1)

10-12: Good consolidation of duplicated class names.

Extracting COMMON_CLASSNAME removes repetition and eases future tweaks.

packages/editor/src/core/plugins/drag-handle.ts (1)

419-420: Switched to public serializeForClipboard – nice!

Using the public API removes the reliance on an internal symbol and future-proofs the plugin.

web/core/components/pages/navigation-pane/tab-panels/root.tsx (1)

7-8: Potential circular / duplicate import path.

This file is itself .../navigation-pane/tab-panels/root.tsx yet imports
@/plane-web/components/pages/navigation-pane/tab-panels/root.
Double-check that it refers to a different module and not to itself through another alias, which would cause unexpected bundler behaviour.

web/core/components/pages/editor/summary/content-browser.tsx (1)

46-46: Fail-safe early-return looks good

Gracefully returning the provided emptyState (or null) when there are no headings prevents unnecessary DOM nodes.
No action required.

packages/editor/src/core/hooks/use-read-only-editor.ts (1)

43-46: Switching immediatelyRender to false can delay the first paint

With read-only editors this is usually fine, but if you rely on the initial HTML being present for layout calculations (e.g. scroll height) you may see a one-frame flash.
Please verify in the page/version screens that the document no longer flickers on mount.

web/core/components/pages/version/editor.tsx (1)

92-98: Rendering nothing when description is empty might be confusing

If a version exists but its description_html is empty, the component returns null, so users see a blank pane instead of a placeholder or “No content” message. Consider falling back to the empty paragraph you already pass to the editor, or showing an explicit notice.

-if (description === undefined || description?.trim() === "") return null;
+if (description === undefined || description.trim() === "") {
+  return (
+    <p className="text-sm text-custom-text-400 px-5 py-4">
+      This version contains no content.
+    </p>
+  );
+}
web/core/components/pages/navigation-pane/tab-panels/info/root.tsx (1)

16-26: Component structure looks solid

Clear separation of document info, actors info and version history keeps the tab panel cohesive. No issues spotted.

web/core/components/pages/editor/editor-body.tsx (1)

92-94: Translation hook addition LGTM

Good to see i18n support for the floating outline button.

web/core/components/pages/navigation-pane/index.ts (1)

1-11: Import path looks CE-specific – confirm alias correctness

"@/plane-web/components/pages/navigation-pane" resolves to the CE layer. If this file is compiled in OSS/EE builds that don’t include that alias, the import will fail. Please double-check that tsconfig.paths maps this alias in every build target.

web/core/components/pages/version/main-content.tsx (1)

111-113: Render guard for VersionEditor during loading

<VersionEditor> receives versionDetails={undefined} on initial render. If the implementation assumes a non-null object this can cause runtime errors. Consider short-circuiting until versionDetails is available or ensure the editor handles undefined.

packages/editor/src/core/helpers/assets.ts (1)

8-9: Path alias likely wrong

"@/plane-editor/constants/assets" looks out of place—the file lives in packages/editor/src/ce/constants/assets.ts.
Double-check the tsconfig path alias; a wrong import will silently yield an empty object, compounding the issue above.

web/core/components/pages/version/root.tsx (1)

31-33: Validate query-param before use

activeVersion comes straight from searchParams. If a malformed value is injected it will propagate to PageVersionsMainContent, potentially triggering an unnecessary network call or even a crash.
Add a simple format check (e.g. UUID/number regex) before passing it downstream.

web/core/components/pages/editor/page-root.tsx (1)

152-160: Double-check prop drilling of version API

PageNavigationPaneRoot receives both isNavigationPaneOpen and versionHistory while the overlay independently fetches version details via the same handlers. Ensure concurrent fetches don’t race or duplicate network traffic.

@aaryan610 aaryan610 marked this pull request as ready for review June 16, 2025 14:32
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🔭 Outside diff range comments (1)
web/core/components/pages/editor/toolbar/options-dropdown.tsx (1)

70-79: Handle copy-to-clipboard failures

copyTextToClipboard returns a promise but any rejection is silently ignored. Surfacing the error helps debugging and gives the user feedback:

-  copyTextToClipboard(editorRef.getMarkDown()).then(() =>
-    setToast({
-      type: TOAST_TYPE.SUCCESS,
-      title: "Success!",
-      message: "Markdown copied to clipboard.",
-    })
-  );
+  copyTextToClipboard(editorRef.getMarkDown())
+    .then(() =>
+      setToast({
+        type: TOAST_TYPE.SUCCESS,
+        title: "Success!",
+        message: "Markdown copied to clipboard.",
+      }),
+    )
+    .catch(() =>
+      setToast({
+        type: TOAST_TYPE.ERROR,
+        title: "Failed!",
+        message: "Unable to copy markdown to clipboard.",
+      }),
+    );
♻️ Duplicate comments (4)
packages/editor/src/core/helpers/assets.ts (1)

13-36: Key-name mismatch with node.type.name still unfixed
(previously reported)

The record is keyed by enum values (IMAGE, CUSTOM_IMAGE) but elsewhere look-ups are done with node.type.name ("image", "customImage").
Unless every caller maps the case manually (they currently don’t, see file-restore/delete plugins), asset discovery will silently fail.

Fix options:

  1. Normalise on access:
const key = node.type.name.toUpperCase() as keyof typeof CORE_ASSETS_META_DATA_RECORD;
CORE_ASSETS_META_DATA_RECORD[key]?.(attrs)
  1. Store the record with the actual node names.

Please address globally.

web/core/components/pages/navigation-pane/tab-panels/assets.tsx (1)

65-90: Nested anchors are still present – invalid HTML & accessibility issue
The outer <a> (href={asset.scrollId}) wraps another <a> used for downloads. This was flagged in the previous review and has not been addressed.

Convert the wrapper to a non-anchor element (<div> or <button> with role="link") and keep the download link as the only anchor.

packages/editor/src/core/hooks/use-editor.ts (2)

194-204: insertText still bails when the selection is empty

Users expect pasted/inserted content to appear at the caret even when nothing is selected.
Re-apply the previously suggested fallback:

-        if (empty) return;
+        if (empty) {
+          editor.chain().focus().insertContent(contentHTML).run();
+          return;
+        }

238-245: Heading-change callback not fired for empty list

The callback is only invoked when headings is truthy, so consumers never learn that the document now has zero headings.

Invoke the callback unconditionally:

-          if (headings) {
-            callback(headings);
-          }
+          callback(headings ?? []);
🧹 Nitpick comments (5)
packages/editor/src/core/hooks/use-collaborative-editor.ts (1)

16-17: Dependency awareness

onAssetChange is forwarded to useEditor, but it’s not memo-ised. If callers pass a new lambda on every render, it could force unnecessary re-subscriptions inside useEditor. Recommend wrapping in useCallback at call-site or documenting this expectation.

packages/editor/src/core/extensions/custom-image/components/image-uploader.tsx (1)

177-178: Missing editor in dependency array

useCallback depends on editor, but only editor.isEditable is listed.
While the instance is usually stable, eslint will still warn and future refactors might break the assumption.

-}, [draggedInside, editor.isEditable, failedToLoadImage, isImageBeingUploaded]);
+}, [draggedInside, editor, failedToLoadImage, isImageBeingUploaded]);
web/core/store/pages/page-editor-info.ts (1)

30-40: Redundant runInAction – action decorators already batch

setEditorRef / updateAssetsList are declared as MobX actions via the decorator, so wrapping the body in an extra runInAction is superfluous.

-  setEditorRef: ... = (editorRef) => {
-    runInAction(() => {
-      this.editorRef = editorRef;
-    });
-  };
+  setEditorRef: ... = (editorRef) => {
+    this.editorRef = editorRef;
+  };

Same for updateAssetsList.

web/core/store/pages/base-page.ts (1)

104-107: Provide a cleanup hook for the new editor sub-store

PageEditorInstance is created but never torn down.
If the class later adds RxJS/MobX reactions or event listeners, the parent BasePage.cleanup() won’t dispose them, leading to memory leaks when pages are unmounted or swapped.

+  cleanup = () => {
+    this.disposers.forEach((disposer) => disposer());
+
+    // optional — call a disposer on the sub-store once it exists
+    if ("cleanup" in this.editor && typeof this.editor.cleanup === "function") {
+      this.editor.cleanup();
+    }
+  };

Adding a pass-through now prevents future surprises and keeps ownership boundaries clear.

web/core/components/pages/navigation-pane/tab-panels/assets.tsx (1)

34-62: Duplicate URL-builder logic – consolidate to avoid drift

getAssetSrc and getAssetDownloadSrc contain identical branching logic differing only in the helper they call. Reduce duplication:

-const buildSrc = (
-  path: string,
-  builder: typeof getEditorAssetSrc | typeof getEditorAssetDownloadSrc
-) => {
+const buildSrc = (
+  path: string,
+  builder: typeof getEditorAssetSrc | typeof getEditorAssetDownloadSrc
+) => {
   if (!path || !workspaceSlug) return "";
   if (path.startsWith("http")) return path;
   return (
     builder({
       assetId: path,
       projectId: project_ids?.[0],
       workspaceSlug: workspaceSlug.toString(),
     }) ?? ""
   );
 };
 
-const getAssetSrc = (path: string) => buildSrc(path, getEditorAssetSrc);
-const getAssetDownloadSrc = (path: string) =>
-  buildSrc(path, getEditorAssetDownloadSrc);
+const getAssetSrc = (path: string) => buildSrc(path, getEditorAssetSrc);
+const getAssetDownloadSrc = (path: string) =>
+  buildSrc(path, getEditorAssetDownloadSrc);

This keeps the two paths in sync and makes future changes less error-prone.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 553aa62 and 37bd7d4.

📒 Files selected for processing (21)
  • packages/editor/src/core/components/editors/document/collaborative-editor.tsx (2 hunks)
  • packages/editor/src/core/extensions/custom-image/components/image-uploader.tsx (3 hunks)
  • packages/editor/src/core/extensions/utility.ts (3 hunks)
  • packages/editor/src/core/helpers/assets.ts (1 hunks)
  • packages/editor/src/core/helpers/editor-ref.ts (1 hunks)
  • packages/editor/src/core/hooks/use-collaborative-editor.ts (2 hunks)
  • packages/editor/src/core/hooks/use-editor.ts (7 hunks)
  • packages/editor/src/core/plugins/file/delete.ts (1 hunks)
  • packages/editor/src/core/plugins/file/restore.ts (2 hunks)
  • packages/editor/src/core/types/collaboration.ts (2 hunks)
  • packages/editor/src/core/types/editor.ts (3 hunks)
  • packages/editor/src/index.ts (0 hunks)
  • web/core/components/pages/editor/editor-body.tsx (7 hunks)
  • web/core/components/pages/editor/page-root.tsx (6 hunks)
  • web/core/components/pages/editor/toolbar/options-dropdown.tsx (1 hunks)
  • web/core/components/pages/editor/toolbar/root.tsx (2 hunks)
  • web/core/components/pages/navigation-pane/tab-panels/assets.tsx (1 hunks)
  • web/core/components/pages/navigation-pane/tab-panels/info/document-info.tsx (1 hunks)
  • web/core/components/pages/navigation-pane/tab-panels/outline.tsx (1 hunks)
  • web/core/store/pages/base-page.ts (4 hunks)
  • web/core/store/pages/page-editor-info.ts (1 hunks)
💤 Files with no reviewable changes (1)
  • packages/editor/src/index.ts
🚧 Files skipped from review as they are similar to previous changes (7)
  • web/core/components/pages/navigation-pane/tab-panels/info/document-info.tsx
  • web/core/components/pages/navigation-pane/tab-panels/outline.tsx
  • packages/editor/src/core/helpers/editor-ref.ts
  • web/core/components/pages/editor/page-root.tsx
  • web/core/components/pages/editor/editor-body.tsx
  • packages/editor/src/core/types/editor.ts
  • web/core/components/pages/editor/toolbar/root.tsx
🧰 Additional context used
🧬 Code Graph Analysis (8)
packages/editor/src/core/types/collaboration.ts (1)
packages/editor/src/core/types/editor.ts (1)
  • TEditorAsset (82-89)
packages/editor/src/core/plugins/file/restore.ts (1)
packages/editor/src/core/helpers/assets.ts (1)
  • CORE_ASSETS_META_DATA_RECORD (13-37)
packages/editor/src/core/extensions/custom-image/components/image-uploader.tsx (1)
packages/editor/src/core/helpers/assets.ts (1)
  • CORE_ASSETS_META_DATA_RECORD (13-37)
packages/editor/src/core/helpers/assets.ts (3)
packages/editor/src/core/types/editor.ts (1)
  • TEditorAsset (82-89)
packages/editor/src/core/extensions/custom-image/components/image-block.tsx (1)
  • getImageBlockId (41-41)
packages/editor/src/ce/constants/assets.ts (1)
  • ADDITIONAL_ASSETS_META_DATA_RECORD (6-6)
packages/editor/src/core/extensions/utility.ts (2)
packages/editor/src/core/types/config.ts (1)
  • TFileHandler (7-19)
packages/editor/src/core/types/editor.ts (1)
  • TEditorAsset (82-89)
web/core/store/pages/page-editor-info.ts (1)
packages/editor/src/core/types/editor.ts (2)
  • TEditorAsset (82-89)
  • EditorRefApi (112-129)
web/core/components/pages/navigation-pane/tab-panels/assets.tsx (7)
web/core/store/pages/base-page.ts (1)
  • TPageInstance (68-71)
packages/editor/src/core/types/editor.ts (1)
  • TEditorAsset (82-89)
packages/i18n/src/hooks/use-translation.ts (1)
  • useTranslation (23-35)
web/core/store/router.store.ts (1)
  • workspaceSlug (69-71)
web/helpers/editor.helper.ts (2)
  • getEditorAssetSrc (14-23)
  • getEditorAssetDownloadSrc (29-38)
packages/utils/src/attachment.ts (1)
  • convertBytesToSize (22-32)
web/core/hooks/use-resolved-asset-path.tsx (1)
  • useResolvedAssetPath (10-26)
web/core/store/pages/base-page.ts (1)
web/core/store/pages/page-editor-info.ts (1)
  • PageEditorInstance (14-41)
🔇 Additional comments (6)
packages/editor/src/core/types/collaboration.ts (1)

38-38: 👍 New onAssetChange prop looks good

The optional callback is clearly typed and keeps backward compatibility.

packages/editor/src/core/plugins/file/delete.ts (1)

60-63: Risk of recursive transactions inside appendTransaction

Invoking editor.commands.updateAssetsList from within appendTransaction dispatches a new transaction, which ProseMirror will feed back through all plugins, including this one. If updateAssetsList sets docChanged false, you’re probably safe, but a future change could create an infinite loop.

Safer pattern: build and return a transaction instead of dispatching, or add a guard meta flag:

editor.commands.updateAssetsList?.({
   idToRemove: node.attrs.id,
+  meta: { skipAssetPlugin: true },
});

and skip when that meta is present.

Consider revisiting the command implementation to eliminate dispatch from plugin callbacks.

packages/editor/src/core/plugins/file/restore.ts (1)

48-53: Same recursion caveat as delete plugin

editor.commands.updateAssetsList is dispatched from appendTransaction, carrying the same recursion / performance risk highlighted for the delete plugin. Consider the same mitigation (returning a transaction or flagging with meta).

packages/editor/src/core/components/editors/document/collaborative-editor.tsx (1)

33-35: Prop drilling looks correct – double-check interface update

onAssetChange and the (re-added) onTransaction are successfully threaded through to useCollaborativeEditor.
Please make sure ICollaborativeDocumentEditor has been updated so both callbacks are declared as optional and properly typed – otherwise TS consumers will wobble.

Also applies to: 64-66

packages/editor/src/core/hooks/use-editor.ts (2)

139-151: Missed empty-state notification & unnecessary re-renders in asset change effect

  1. if (!assets || !onAssetChange) return; skips the callback when assets is an empty array, hiding “no assets” transitions.
  2. useEditorState returns a new object each time; comparing assetsList?.assets by reference may trigger the useEffect even when contents are unchanged.
-  const assets = assetsList?.assets;
-  if (!assets || !onAssetChange) return;
-  onAssetChange(assets);
+  const assets = assetsList?.assets ?? [];
+  if (!onAssetChange) return;
+  onAssetChange(assets);

Consider using a stable comparison (e.g., hashing or lodash/isEqual) inside selector to avoid spurious updates.


217-218: 👍 Guard clause implemented

listenToRealTimeUpdate now safely returns undefined when provider is absent, preventing runtime errors flagged earlier.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (1)
space/styles/globals.css (1)

370-370: Global smooth scrolling may conflict with user preferences
Applying scroll-behavior: smooth; on * overrides prefers-reduced-motion and can cause unexpected behavior in nested scroll containers. Consider scoping it to html and respecting motion-reduction preferences:

/* remove from universal selector */
* {
  /* … */
  /* scroll-behavior: smooth; */
}

/* add scoped, accessible smooth scrolling */
@media (prefers-reduced-motion: no-preference) {
  html {
    scroll-behavior: smooth;
  }
}
@media (prefers-reduced-motion: reduce) {
  html {
    scroll-behavior: auto;
  }
}
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6640b57 and ab2e5ff.

📒 Files selected for processing (6)
  • admin/styles/globals.css (1 hunks)
  • space/styles/globals.css (2 hunks)
  • web/core/components/pages/editor/editor-body.tsx (7 hunks)
  • web/core/components/pages/navigation-pane/root.tsx (1 hunks)
  • web/core/components/pages/navigation-pane/tab-panels/assets.tsx (1 hunks)
  • web/core/components/pages/navigation-pane/tab-panels/info/version-history.tsx (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • admin/styles/globals.css
🚧 Files skipped from review as they are similar to previous changes (4)
  • web/core/components/pages/editor/editor-body.tsx
  • web/core/components/pages/navigation-pane/root.tsx
  • web/core/components/pages/navigation-pane/tab-panels/assets.tsx
  • web/core/components/pages/navigation-pane/tab-panels/info/version-history.tsx
⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: Analyze (javascript)
🔇 Additional comments (1)
space/styles/globals.css (1)

50-75: Reformatted shadow variable declarations
The move from single‐line to multi‐line for --color-shadow-* enhances readability without altering values. Indentation and trailing commas appear consistent and valid. No functional impact detected.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

♻️ Duplicate comments (1)
web/core/components/pages/navigation-pane/tab-panels/assets.tsx (1)

66-91: Nested <a> elements – invalid & inaccessible HTML

The outer anchor (<a href={asset.href}>) wraps another anchor (<a href={getAssetDownloadSrc(...)}), re-introducing the exact issue called out in the previous review: nested anchors are not allowed and break keyboard / screen-reader semantics.
Convert the outer anchor into a non-anchor element (<div> or <button> with role="link" + click handler) so that only one interactive anchor remains.

-    return (
-      <a
-        href={asset.href}
-        className="relative group/asset-item h-12 flex items-center gap-2 pr-2 rounded border border-custom-border-200 hover:bg-custom-background-80 transition-colors"
-      >
+    return (
+      <div
+        role="link"
+        tabIndex={0}
+        onClick={() => document.querySelector(asset.href)?.scrollIntoView({ behavior: "smooth" })}
+        className="relative group/asset-item h-12 flex items-center gap-2 pr-2 rounded border border-custom-border-200 hover:bg-custom-background-80 transition-colors"
+      >
        ...
-      </a>
+      </div>
🧹 Nitpick comments (2)
web/core/components/pages/navigation-pane/tab-panels/assets.tsx (2)

34-61: Duplicate URL-resolution logic – extract helper to reduce noise

getAssetSrc and getAssetDownloadSrc are identical except for the wrapped util. Consider a single factory/helper to keep the component lean:

-  const getAssetSrc = (path: string) => { ... }
-  const getAssetDownloadSrc = (path: string) => { ... }
+  const resolveSrc = (
+    path: string,
+    resolver: typeof getEditorAssetSrc | typeof getEditorAssetDownloadSrc,
+  ) => {
+    if (!path || !workspaceSlug) return "";
+    return path.startsWith("http")
+      ? path
+      : resolver({
+          assetId: path,
+          projectId: project_ids?.[0],
+          workspaceSlug: workspaceSlug.toString(),
+        }) ?? "";
+  };

This removes duplication and prevents future drift between the two implementations.


81-83: Add download attribute for explicit download behaviour

Browsers will attempt to navigate if the Content-Disposition header is missing. Adding download hints the intent and improves UX:

-      <a
+      <a
+        download
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 68f902c and 28b867c.

📒 Files selected for processing (7)
  • packages/editor/src/ce/types/asset.ts (1 hunks)
  • packages/editor/src/core/helpers/assets.ts (1 hunks)
  • packages/editor/src/core/types/asset.ts (1 hunks)
  • packages/editor/src/core/types/editor.ts (4 hunks)
  • packages/editor/src/core/types/index.ts (1 hunks)
  • packages/editor/src/index.ts (1 hunks)
  • web/core/components/pages/navigation-pane/tab-panels/assets.tsx (1 hunks)
✅ Files skipped from review due to trivial changes (3)
  • packages/editor/src/ce/types/asset.ts
  • packages/editor/src/core/types/index.ts
  • packages/editor/src/core/types/asset.ts
🚧 Files skipped from review as they are similar to previous changes (3)
  • packages/editor/src/index.ts
  • packages/editor/src/core/helpers/assets.ts
  • packages/editor/src/core/types/editor.ts
🧰 Additional context used
🧬 Code Graph Analysis (1)
web/core/components/pages/navigation-pane/tab-panels/assets.tsx (6)
web/core/store/pages/base-page.ts (1)
  • TPageInstance (68-71)
packages/editor/src/core/types/asset.ts (1)
  • TEditorAsset (14-14)
packages/i18n/src/hooks/use-translation.ts (1)
  • useTranslation (23-35)
packages/utils/src/editor.ts (1)
  • getEditorAssetDownloadSrc (29-38)
web/ce/components/pages/navigation-pane/tab-panels/assets.tsx (1)
  • AdditionalPageNavigationPaneAssetItem (11-11)
web/core/hooks/use-resolved-asset-path.tsx (1)
  • useResolvedAssetPath (10-26)
⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: Analyze (javascript)

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 441f237 and 2f6b42d.

📒 Files selected for processing (4)
  • web/ce/components/pages/navigation-pane/tab-panels/empty-states/assets.tsx (1 hunks)
  • web/ce/components/pages/navigation-pane/tab-panels/empty-states/outline.tsx (1 hunks)
  • web/core/components/pages/navigation-pane/tab-panels/assets.tsx (1 hunks)
  • web/core/components/pages/navigation-pane/tab-panels/outline.tsx (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • web/ce/components/pages/navigation-pane/tab-panels/empty-states/outline.tsx
🚧 Files skipped from review as they are similar to previous changes (2)
  • web/core/components/pages/navigation-pane/tab-panels/outline.tsx
  • web/core/components/pages/navigation-pane/tab-panels/assets.tsx
🔇 Additional comments (3)
web/ce/components/pages/navigation-pane/tab-panels/empty-states/assets.tsx (3)

1-5: LGTM! Import statements are well-organized.

The imports are appropriate for the component's functionality, including Next.js Image optimization, internationalization, and custom asset path resolution.


7-7: LGTM! Component naming follows established conventions.

The component name clearly describes its purpose within the page navigation pane feature hierarchy.


13-25: LGTM! Well-structured JSX with proper accessibility and styling.

The component implements:

  • Proper centering using CSS Grid and Flexbox
  • Semantic HTML structure with appropriate heading hierarchy
  • Accessibility compliance with descriptive alt text
  • Consistent styling with Tailwind CSS classes
  • Proper translation key namespacing

@sriramveeraghanta sriramveeraghanta merged commit 0b159c4 into preview Jul 2, 2025
5 of 6 checks passed
@sriramveeraghanta sriramveeraghanta deleted the feat/page-navigation-pane branch July 2, 2025 09:55
lifeiscontent pushed a commit that referenced this pull request Aug 18, 2025
* init: page navigation pane

* chore: outline and info tabs

* chore: asset download endpoint

* chore: realtime document info updates

* chore: add support for code splitting

* fix: formatting

* refactor: image block id generation

* chore: implement translation

* refactor: assets list storage logic

* fix: build errors

* fix: image extension name

* refactor: add support for additional asset items

* refactor: asset extraction logic

* chore: add translations

* fix: merge conflicts resolved from preview

* chore: remove version history option from the dropdown

* chore: query params handling

* chore: remove unnecessary logic

* refactor: empty state components

* fix: empty state asset path
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants