Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Set home page for space#1666

Open
Eshwar1212-maker wants to merge 5 commits intodocmost:mainfrom
Eshwar1212-maker:set-home-page-for-space
Open

Set home page for space#1666
Eshwar1212-maker wants to merge 5 commits intodocmost:mainfrom
Eshwar1212-maker:set-home-page-for-space

Conversation

@Eshwar1212-maker
Copy link
Contributor

@Eshwar1212-maker Eshwar1212-maker commented Oct 7, 2025

Screen.Recording.2025-10-07.at.1.11.14.PM.mov

This PR gives the user and ability to mark any specific page in a space as the home page as requested in this ticket #1646

-A user can mark a page in the space as the homepage with a whole icon that I added in the 'page-header' component.

-Every time a user has a home page for a space it directs them to that page instead of the overview page.

-If a home page is not set the user gets directed to the overview page instead.

https://github.com/user-attachments/assets/943e59f8-82f3-4773-983c-17d323f5673a.

Summary by CodeRabbit

  • New Features
    • You can now set or unset a space’s home page directly from the page header (Home button with tooltip).
  • Improvements
    • Space cards open directly to the designated home page when one is set, streamlining navigation.
    • More robust handling when updating a space’s home page to prevent invalid selections.

@coderabbitai
Copy link

coderabbitai bot commented Oct 7, 2025

Walkthrough

Adds “home page” support across client and server: UI toggle in PageHeaderMenu, props plumbed through PageHeader and page container, conditional space card navigation, ISpace type update, server DTO/service validation and persistence for homePageId, and database type additions for Spaces and related tables.

Changes

Cohort / File(s) Summary of changes
Client: Header home toggle
apps/client/src/features/page/components/header/page-header-menu.tsx, apps/client/src/features/page/components/header/page-header.tsx
Added isHome, spaceId, pageId props; introduced local isHome state; wired useUpdateSpaceMutation to set/unset space.homePageId; rendered Home icon button; forwarded new props from PageHeader to PageHeaderMenu.
Client: Page wiring
apps/client/src/pages/page/page.tsx
Computed isHomePage via space.homePageId === page.id; passed isHome, spaceId, pageId to MemoizedPageHeader.
Client: Space navigation
apps/client/src/features/space/components/space-grid.tsx
Link now targets space home page when homePageId exists; otherwise falls back to getSpaceUrl(space.slug).
Client: Space types
apps/client/src/features/space/types/space.types.ts
Added optional homePageId?: string to ISpace.
Server: Space update & validation
apps/server/src/core/space/dto/update-space.dto.ts, apps/server/src/core/space/services/space.service.ts
DTO: added optional homePageId with @IsUUID and @IsOptional (string
Server: DB types
apps/server/src/database/types/db.d.ts
Expanded DB typings: added Spaces.homePageId and openSectionsByDefault; added Users.hasGeneratedPassword; updated AuthProviders fields; introduced ApiKeys; minor formatting/import tweaks; updated DB interface accordingly.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor U as User
  participant PH as PageHeaderMenu (Client)
  participant C as Client API Layer
  participant S as SpaceService (Server)
  participant PR as PageRepo
  participant SR as SpaceRepo

  U->>PH: Click "Home" toggle
  PH->>C: mutate updateSpace({ spaceId, homePageId or null })
  rect rgba(200,230,255,0.3)
    C->>S: PATCH /spaces/:id { homePageId }
    S->>S: Validate DTO (UUID/optional)
    alt homePageId provided
      S->>PR: getById(homePageId)
      PR-->>S: page | null
      alt page not found
        S-->>C: 400 BadRequest (invalid homePageId)
        C-->>PH: error
        note right of PH: Keep local state unchanged
      else page found
        S->>SR: updateSpace({ id, homePageId })
        SR-->>S: updated space
        S-->>C: 200 OK { space }
        C-->>PH: success
        PH->>PH: setIsHomePage(true/false)
      end
    else homePageId null/omitted
      S->>SR: updateSpace({ id, homePageId: null })
      SR-->>S: updated space
      S-->>C: 200 OK
      C-->>PH: success
      PH->>PH: setIsHomePage(false)
    end
  end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

I thump my paws: a home at last!
A page to greet each browsing blast.
Flip the switch—hop, hop—so sweet,
Spaces know which door to meet.
Links align, the carrots chime,
Home is set—commit in time. 🥕✨

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The title clearly and succinctly summarizes the primary feature change by indicating the addition of the capability to set a home page for a space, matching the core intent of the pull request without extraneous detail.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

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.

Copy link

@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: 5

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
apps/server/src/core/space/services/space.service.ts (1)

108-117: Add validation for homePageId before persisting.

The service persists homePageId without validating that:

  1. The page actually exists
  2. The page belongs to the space being updated

This could allow setting a non-existent page or a page from a different space as the home page, leading to broken navigation and data integrity issues.

Add validation before the update. Example implementation:

async updateSpace(
  updateSpaceDto: UpdateSpaceDto,
  workspaceId: string,
): Promise<Space> {
  if (updateSpaceDto?.slug) {
    const slugExists = await this.spaceRepo.slugExists(
      updateSpaceDto.slug,
      workspaceId,
    );

    if (slugExists) {
      throw new BadRequestException(
        'Space slug exists. Please use a unique space slug',
      );
    }
  }

  // Validate homePageId if provided
  if (updateSpaceDto?.homePageId) {
    const page = await this.pageRepo.findById(
      updateSpaceDto.homePageId,
      workspaceId,
    );
    
    if (!page || page.spaceId !== updateSpaceDto.spaceId) {
      throw new BadRequestException(
        'Invalid home page: page does not exist or does not belong to this space',
      );
    }
  }

  return await this.spaceRepo.updateSpace(
    {
      name: updateSpaceDto.name,
      description: updateSpaceDto.description,
      slug: updateSpaceDto.slug,
      homePageId: updateSpaceDto.homePageId
    },
    updateSpaceDto.spaceId,
    workspaceId,
  );
}
apps/client/src/features/page/components/header/page-header-menu.tsx (1)

55-105: Guard optional props before mutating space state

isHome, spaceId, and pageId are all optional yet the new logic assumes they are defined. Today this compiles because the props are typed as optional, but at runtime we immediately feed them into useState<boolean>(isHome) and setIsHomePage(isHome) (Line 67 / Line 103). When isHome is undefined (the default for spaces without a home page), React receives undefined where a boolean is required. TypeScript also rejects this under strictNullChecks, so the build will break.

Additionally, when the user marks a page as the home page, we send { homePageId: pageId }. If pageId or spaceId is missing (which can happen because they are optional), we end up hitting the mutation with undefined, leading to a backend validation error and leaving the UI out of sync.

Please normalise the props before use (default isHome to false) and bail out early if either spaceId or pageId is missing so we never fire an invalid update. Example fix:

-const [isHomePage, setIsHomePage] = useState<boolean>(isHome);
+const [isHomePage, setIsHomePage] = useState<boolean>(Boolean(isHome));-const handleUpdateHomePage = async () => {
-  const newHomePageValue = isHomePage ? null : pageId;
-  const spaceData: Partial<ISpace> = {
-    spaceId: spaceId,
-    homePageId: newHomePageValue,
-  };
-
-  await updateSpaceMutation.mutateAsync(spaceData);
-  setIsHomePage(!isHomePage);
-};
+const handleUpdateHomePage = async () => {
+  if (!spaceId || !pageId) {
+    return;
+  }
+
+  const newHomePageValue = isHomePage ? null : pageId;
+  await updateSpaceMutation.mutateAsync({
+    spaceId,
+    homePageId: newHomePageValue,
+  });
+  setIsHomePage((current) => !current);
+};-useEffect(() => {
-  setIsHomePage(isHome);
-}, [isHome]);
+useEffect(() => {
+  setIsHomePage(Boolean(isHome));
+}, [isHome]);

This keeps state strictly boolean and prevents accidental mutation calls with undefined identifiers.

♻️ Duplicate comments (1)
apps/server/src/database/migrations/20251005T160503-20251005-add-home-page.ts (1)

1-7: Remove duplicate empty migration.

Same issue as 20251005T160001-20251005-add-home-page.ts: this is another empty placeholder migration with no logic. Having three migration files for the same feature (two empty, one functional) creates unnecessary clutter.

Remove this file and consolidate to a single functional migration.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 042836c and 0914fae.

📒 Files selected for processing (11)
  • apps/client/src/features/page/components/header/page-header-menu.tsx (5 hunks)
  • apps/client/src/features/page/components/header/page-header.tsx (1 hunks)
  • apps/client/src/features/space/components/space-grid.tsx (1 hunks)
  • apps/client/src/features/space/types/space.types.ts (1 hunks)
  • apps/client/src/pages/page/page.tsx (2 hunks)
  • apps/server/src/core/space/dto/update-space.dto.ts (1 hunks)
  • apps/server/src/core/space/services/space.service.ts (1 hunks)
  • apps/server/src/database/migrations/20251005T151245-add-home-page.ts.ts (1 hunks)
  • apps/server/src/database/migrations/20251005T160001-20251005-add-home-page.ts (1 hunks)
  • apps/server/src/database/migrations/20251005T160503-20251005-add-home-page.ts (1 hunks)
  • apps/server/src/database/types/db.d.ts (3 hunks)
🧰 Additional context used
🧬 Code graph analysis (8)
apps/server/src/database/migrations/20251005T151245-add-home-page.ts.ts (2)
apps/server/src/database/migrations/20251005T160001-20251005-add-home-page.ts (2)
  • up (3-4)
  • down (6-7)
apps/server/src/database/migrations/20251005T160503-20251005-add-home-page.ts (2)
  • up (3-4)
  • down (6-7)
apps/client/src/pages/page/page.tsx (3)
apps/client/src/features/page/queries/page-query.ts (1)
  • usePageQuery (43-64)
apps/client/src/lib/utils.tsx (1)
  • extractPageSlugId (15-24)
apps/client/src/features/space/queries/space-query.ts (1)
  • useGetSpaceBySlugQuery (98-107)
apps/client/src/features/page/components/header/page-header.tsx (1)
apps/client/src/features/page/components/header/page-header-menu.tsx (1)
  • PageHeaderMenu (58-165)
apps/server/src/core/space/dto/update-space.dto.ts (1)
apps/server/src/core/space/dto/create-space.dto.ts (1)
  • CreateSpaceDto (10-25)
apps/server/src/database/migrations/20251005T160503-20251005-add-home-page.ts (2)
apps/server/src/database/migrations/20251005T151245-add-home-page.ts.ts (2)
  • up (3-8)
  • down (10-15)
apps/server/src/database/migrations/20251005T160001-20251005-add-home-page.ts (2)
  • up (3-4)
  • down (6-7)
apps/client/src/features/space/components/space-grid.tsx (1)
apps/client/src/lib/config.ts (1)
  • getSpaceUrl (55-57)
apps/client/src/features/page/components/header/page-header-menu.tsx (3)
apps/client/src/features/editor/atoms/editor-atoms.ts (1)
  • yjsConnectionStatusAtom (10-10)
apps/client/src/features/space/queries/space-query.ts (1)
  • useUpdateSpaceMutation (109-137)
apps/client/src/features/space/types/space.types.ts (1)
  • ISpace (8-22)
apps/server/src/database/migrations/20251005T160001-20251005-add-home-page.ts (2)
apps/server/src/database/migrations/20251005T151245-add-home-page.ts.ts (2)
  • up (3-8)
  • down (10-15)
apps/server/src/database/migrations/20251005T160503-20251005-add-home-page.ts (2)
  • up (3-4)
  • down (6-7)
🔇 Additional comments (2)
apps/client/src/features/space/types/space.types.ts (1)

21-21: LGTM!

The addition of the optional homePageId field to the ISpace interface is correct and aligns with the server-side schema changes.

apps/client/src/pages/page/page.tsx (1)

65-67: LGTM!

The props passed to MemoizedPageHeader correctly provide the home page context and necessary identifiers for the header component to function properly.

Copy link

@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: 2

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 724ae58 and 3e8d263.

📒 Files selected for processing (4)
  • apps/client/src/features/space/components/space-grid.tsx (1 hunks)
  • apps/client/src/pages/page/page.tsx (2 hunks)
  • apps/server/src/core/space/services/space.service.ts (2 hunks)
  • apps/server/src/database/migrations/20251005T151245-add-home-page.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • apps/client/src/pages/page/page.tsx
  • apps/client/src/features/space/components/space-grid.tsx
🧰 Additional context used
🧬 Code graph analysis (1)
apps/server/src/core/space/services/space.service.ts (2)
apps/server/src/database/repos/page/page.repo.ts (1)
  • Injectable (18-425)
apps/server/src/database/repos/space/space.repo.ts (1)
  • Injectable (16-159)
🔇 Additional comments (3)
apps/server/src/core/space/services/space.service.ts (3)

20-20: LGTM!

PageRepo import is correct and necessary for the home page validation logic.


26-26: LGTM!

PageRepo injection is correct and follows NestJS dependency injection patterns.


124-124: No action required: UpdateSpaceDto.homePageId already supports explicit null
UpdateSpaceDto.homePageId is typed as string | null, so clients can clear the home page by passing null.

@Vito0912
Copy link
Contributor

Vito0912 commented Oct 8, 2025

Disclaimer: I am not a maintainer

I love that feature!

But I don't think the button is placed that well. The bar already is overloaded and setting a home page probably isn't going to be an often used action. So imho I think it would better fit in the dot menu instead.

@Eshwar1212-maker
Copy link
Contributor Author

@Vito0912 Yeah thats totally doable to, i thought where it is now is good but we will see what the maintainer says.

@Eshwar1212-maker Eshwar1212-maker force-pushed the set-home-page-for-space branch 3 times, most recently from 8ca23ad to 0914fae Compare October 12, 2025 17:13
Copy link

@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: 2

🧹 Nitpick comments (3)
apps/client/src/features/page/components/header/page-header-menu.tsx (3)

48-48: Remove unused import.

The updateSpace function is imported but never used in this component. The mutation hook useUpdateSpaceMutation is used instead on line 69.

Apply this diff to remove the unused import:

-import { updateSpace } from "@/features/space/services/space-service";

98-99: Wrap mutation in try-catch to prevent unhandled errors.

While the mutation hook handles error notifications, the function should catch potential errors to prevent unhandled promise rejections and ensure graceful degradation.

Apply this diff:

+   try {
      await updateSpaceMutation.mutateAsync(spaceData);
      setIsHomePage(!isHomePage);
+   } catch (error) {
+     // Error notification already shown by mutation hook
+     console.error('Failed to update home page:', error);
+   }

130-134: Use theme colors instead of hard-coded color strings.

The color: "lightblue" is not theme-aware and may have poor contrast in dark mode or other themes. Use Mantine's theme colors for better consistency.

Apply this diff:

          <IconHome
            size={20}
            stroke={2}
-           {...(isHomePage ? { color: "lightblue" } : {})}
+           {...(isHomePage ? { color: "var(--mantine-color-blue-5)" } : {})}
          />

Or alternatively, use Mantine's c prop for better theming:

-        <ActionIcon
+        <ActionIcon
           variant="default"
           style={{ border: "none" }}
           onClick={handleUpdateHomePage}
+          {...(isHomePage ? { color: "blue" } : {})}
         >
           <IconHome
             size={20}
             stroke={2}
-            {...(isHomePage ? { color: "lightblue" } : {})}
           />
         </ActionIcon>
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 08df3a2 and a3c00b5.

📒 Files selected for processing (1)
  • apps/client/src/features/page/components/header/page-header-menu.tsx (5 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
apps/client/src/features/page/components/header/page-header-menu.tsx (3)
apps/client/src/features/editor/atoms/editor-atoms.ts (1)
  • yjsConnectionStatusAtom (10-10)
apps/client/src/features/space/queries/space-query.ts (1)
  • useUpdateSpaceMutation (109-137)
apps/client/src/features/space/types/space.types.ts (1)
  • ISpace (8-22)
🔇 Additional comments (1)
apps/client/src/features/page/components/header/page-header-menu.tsx (1)

120-136: Consider the UX feedback about button placement.

A community member (Vito0912) raised a valid concern that the page header is crowded and setting a home page is an infrequent action. They suggested moving this control to the overflow menu (the three-dot menu) instead of the visible header bar.

This is primarily a UX/design decision, but worth considering whether the home page toggle would be better placed in the PageActionMenu component alongside other page actions.

Current placement pros:

  • More discoverable for users
  • Quicker access

Overflow menu pros:

  • Reduces header clutter
  • Groups related page settings together
  • Aligns with infrequent usage pattern

Please confirm the intended placement with the maintainers before merging.

const { t } = useTranslation();
const toggleAside = useToggleAside();
const [yjsConnectionStatus] = useAtom(yjsConnectionStatusAtom);
const [isHomePage, setIsHomePage] = useState<boolean>(isHome);
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

State may become stale if prop changes.

The isHomePage state is initialized from the isHome prop but won't update if the prop changes later. If the home page is updated elsewhere (e.g., via another component or tab), this component will show stale state.

Consider one of these solutions:

Solution 1 (preferred): Derive the value directly from the prop

-  const [isHomePage, setIsHomePage] = useState<boolean>(isHome);

Then use isHome directly in the component and update the mutation's success callback to rely on query cache updates.

Solution 2: Sync state with prop using useEffect

+  useEffect(() => {
+    setIsHomePage(isHome);
+  }, [isHome]);

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In apps/client/src/features/page/components/header/page-header-menu.tsx around
line 67, the component initializes local state const [isHomePage, setIsHomePage]
= useState<boolean>(isHome) which will become stale if the isHome prop changes;
fix by removing the derived local state and use the isHome prop directly
throughout the component (and update the mutation success handler to rely on
query-cache updates or explicitly update cache/ui there), or if you must keep
local state, add a useEffect(() => setIsHomePage(isHome), [isHome]) so the state
stays in sync with the prop and adjust any handlers to update both local state
and cache consistently.

Comment on lines +91 to +100
const handleUpdateHomePage = async () => {
const newHomePageValue = isHomePage ? null : pageId;
const spaceData: Partial<ISpace> = {
spaceId: spaceId,
homePageId: newHomePageValue,
};

await updateSpaceMutation.mutateAsync(spaceData);
setIsHomePage(!isHomePage);
};
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Add validation for required props.

The function uses spaceId and pageId without checking if they're defined. If these props are missing, the mutation will fail with unclear errors.

Apply this diff to add prop validation:

  const handleUpdateHomePage = async () => {
+   if (!spaceId || !pageId) {
+     notifications.show({ 
+       message: t("Unable to update home page"), 
+       color: "red" 
+     });
+     return;
+   }
+
    const newHomePageValue = isHomePage ? null : pageId;
    const spaceData: Partial<ISpace> = {
      spaceId: spaceId,
      homePageId: newHomePageValue,
    };

    await updateSpaceMutation.mutateAsync(spaceData);
    setIsHomePage(!isHomePage);
  };
🤖 Prompt for AI Agents
In apps/client/src/features/page/components/header/page-header-menu.tsx around
lines 91 to 100, validate that required props spaceId and pageId are present
before calling updateSpaceMutation: check if spaceId is defined (and pageId when
setting home) and if not, abort the handler early (return) and surface a clear
error (e.g., show a user-facing message or log a descriptive error) rather than
calling mutateAsync with undefined values; only build spaceData and call
updateSpaceMutation.mutateAsync when validation passes and keep toggling
isHomePage after a successful mutation.

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