Skip to content

Conversation

@niko91i
Copy link
Contributor

@niko91i niko91i commented Jan 5, 2026

Description

Hide the "Add channel" button in the channel switcher dropdown for users who don't have the CreateChannel permission.

Problem: Currently, all users see the "Add channel" option in the channel selector menu, even seller/vendor admins who don't have permission to create channels. This causes confusion as they can access the form but cannot submit it.

Solution: Wrap the "Add channel" menu item (and its separator) with <PermissionGuard requires={['CreateChannel']}> to conditionally render it only for users with the appropriate permission. This follows the same pattern used elsewhere in the Dashboard (e.g., global-views-bar.tsx).

Fixes #4056

Breaking changes

No breaking changes.

Screenshots

N/A - The "Add channel" option simply no longer appears for users without the CreateChannel permission.

Checklist

📌 Always:

  • I have set a clear title
  • My PR is small and contains a single feature
  • I have checked my own PR

@vercel
Copy link

vercel bot commented Jan 5, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Review Updated (UTC)
docs Ready Ready Preview Jan 7, 2026 3:47pm
vendure-storybook Ready Ready Preview, Comment Jan 7, 2026 3:47pm

@github-actions
Copy link
Contributor

github-actions bot commented Jan 5, 2026

All contributors have signed the CLA ✍️ ✅
Posted by the CLA Assistant Lite bot.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 5, 2026

Caution

Review failed

The pull request is closed.

📝 Walkthrough

Walkthrough

The change wraps the "Add channel" menu item and its preceding separator in a PermissionGuard requiring the CreateChannel permission, so both elements are rendered only for users granted that permission. No other UI elements, behavior, or public APIs were modified.

Changes

Cohort / File(s) Summary
Channel switcher permission guard
packages/dashboard/src/lib/components/layout/channel-switcher.tsx
Imported PermissionGuard and moved the menu separator and the "Add channel" menu item inside a PermissionGuard requires={['CreateChannel']} so they render only for users with the CreateChannel permission.
🚥 Pre-merge checks | ✅ 3 | ❌ 2
❌ Failed checks (2 warnings)
Check name Status Explanation Resolution
Linked Issues check ⚠️ Warning The PR partially addresses issue #4056 by hiding the 'Add channel' button for unauthorized users, but does not address auto-selecting a single channel or hiding the channel creation page. This PR only fixes visibility of the 'Add channel' option; consider addressing the other requirements from #4056 (auto-select single channel, hide channel creation page) in separate PRs.
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 (3 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely describes the main change: hiding the 'Add channel' button for unauthorized users based on missing CreateChannel permission.
Description check ✅ Passed The PR description includes all required template sections with clear content: summary of changes, linked issue reference, breaking changes statement, screenshots section, and completed checklist.
Out of Scope Changes check ✅ Passed All changes are scoped to hiding the 'Add channel' button with PermissionGuard wrapper, directly addressing the specific requirement mentioned in the PR objectives.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings

📜 Recent review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b7af4f5 and 40b91e4.

📒 Files selected for processing (1)
  • packages/dashboard/src/lib/components/layout/channel-switcher.tsx

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.

@niko91i
Copy link
Contributor Author

niko91i commented Jan 5, 2026

I have read the CLA Document and I hereby sign the CLA

@michaelbromley
Copy link
Member

Hi! Thanks for this and I'm ready to merge it, but the CLA bot is unhappy because the commit was not made with the same user that signed the CLA

image

Can you sort that out?

@niko91i
Copy link
Contributor Author

niko91i commented Jan 7, 2026

I have read the CLA Document and I hereby sign the CLA

@niko91i niko91i force-pushed the fix/hide-add-channel-without-permission branch from eca0310 to b7af4f5 Compare January 7, 2026 13:46
@niko91i
Copy link
Contributor Author

niko91i commented Jan 7, 2026

Fixed 👌

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

🤖 Fix all issues with AI agents
In @packages/dashboard/src/lib/components/layout/channel-switcher.tsx:
- Around line 198-210: The submit button permission check uses a fixed
['UpdateChannel'] which hides the button when creating a new channel; update the
PermissionGuard around the submit action to use a conditional requires prop that
uses ['CreateChannel'] when creatingNewEntity is true and ['UpdateChannel']
otherwise (i.e., change the requires prop on PermissionGuard to depend on
creatingNewEntity). Ensure this logic is applied where PermissionGuard is used
for the channel form submit button and aligns with the backend mutation
permission.
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between eca0310 and b7af4f5.

📒 Files selected for processing (1)
  • packages/dashboard/src/lib/components/layout/channel-switcher.tsx
🧰 Additional context used
📓 Path-based instructions (2)
packages/dashboard/src/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/dashboard.mdc)

packages/dashboard/src/**/*.{ts,tsx}: Use React as the UI framework for components in the dashboard package
Use TanStack Query (useQuery or useMutation) for data fetching, not Apollo Client
Import api from '@/graphql/api.js' and graphql from '@/graphql/graphql.js' for GraphQL queries and mutations
Use the api.query() pattern with graphql document when creating useQuery calls, including queryKey and staleTime configuration
Use the api.mutate() pattern with graphql document when creating useMutation calls, with onSuccess and onError handlers
Use FormFieldWrapper component for form controls instead of raw Shadcn react-hook-form components
Use @lingui/react/macro for localization with Trans component for markup and useLingui hook for programmatic strings
Set React component props objects to Readonly<> type for type safety

Files:

  • packages/dashboard/src/lib/components/layout/channel-switcher.tsx
packages/dashboard/src/**/*.{ts,tsx,css}

📄 CodeRabbit inference engine (.cursor/rules/dashboard.mdc)

Use Shadcn UI & Tailwind CSS for styling and UI components in the dashboard

Files:

  • packages/dashboard/src/lib/components/layout/channel-switcher.tsx
🧬 Code graph analysis (1)
packages/dashboard/src/lib/components/layout/channel-switcher.tsx (2)
packages/dashboard/src/lib/components/shared/permission-guard.tsx (1)
  • PermissionGuard (44-51)
packages/dashboard/src/lib/components/ui/dropdown-menu.tsx (2)
  • DropdownMenuSeparator (217-217)
  • DropdownMenuItem (212-212)
🔇 Additional comments (1)
packages/dashboard/src/lib/components/layout/channel-switcher.tsx (1)

4-4: LGTM! Correct import added.

The PermissionGuard import is correctly added to support the permission-based rendering of the "Add channel" menu item.

Comment on lines 198 to 210
<PermissionGuard requires={['CreateChannel']}>
<DropdownMenuSeparator />
<DropdownMenuItem className="gap-2 p-2 cursor-pointer" asChild>
<Link to={'/channels/new'}>
<div className="bg-background flex size-6 items-center justify-center rounded-md border">
<Plus className="size-4" />
</div>
<div className="text-muted-foreground font-medium">
<Trans>Add channel</Trans>
</div>
</Link>
</DropdownMenuItem>
</PermissionGuard>
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Search for route definition and channel creation page

echo "=== Searching for /channels/new route definition ==="
rg -n "channels/new" --type=tsx --type=ts -g '!node_modules' -g '!*.test.*' -g '!*.spec.*'

echo ""
echo "=== Looking for route files ==="
find packages/dashboard/src -type f -name "*route*" -o -name "*Router*" | head -20

echo ""
echo "=== Checking for pages directory ==="
find packages/dashboard/src -type d -name "pages" -o -type d -name "route*"

Repository: vendurehq/vendure

Length of output: 444


🏁 Script executed:

#!/bin/bash
# Search for channel creation related files and pages

echo "=== Searching for files matching 'new' in channels directory ==="
fd -e tsx -e ts "new" packages/dashboard/src -g "*channel*"

echo ""
echo "=== Listing channel-related source files ==="
fd -e tsx -e ts "channel" packages/dashboard/src --type f | grep -v node_modules | head -30

Repository: vendurehq/vendure

Length of output: 1236


🏁 Script executed:

#!/bin/bash
# Search for PermissionGuard usage in page components

echo "=== Searching for PermissionGuard in dashboard pages ==="
rg -n "PermissionGuard" packages/dashboard/src --type=tsx --type=ts -C 3 | head -100

echo ""
echo "=== Searching for route configuration files ==="
find packages/dashboard/src -type f \( -name "*.config.*" -o -name "*route*" -o -name "*Router*" \) | grep -v node_modules

Repository: vendurehq/vendure

Length of output: 392


🏁 Script executed:

#!/bin/bash
# Check the route tree file
echo "=== Checking routeTree.gen.ts for channel routes ==="
cat packages/dashboard/src/app/routeTree.gen.ts | grep -i channel -C 3 | head -50

echo ""
echo "=== Checking channels.tsx file ==="
head -100 packages/dashboard/src/app/routes/_authenticated/_channels/channels.tsx

echo ""
echo "=== Checking for new channel route or modal ==="
rg "new.*channel|channel.*new" packages/dashboard/src/app/routes -i -A 5 | head -80

Repository: vendurehq/vendure

Length of output: 11172


🏁 Script executed:

#!/bin/bash
# Look for the destination of the Link in channel-switcher
echo "=== Check full channel-switcher.tsx file context around line 205 ==="
sed -n '190,220p' packages/dashboard/src/lib/components/layout/channel-switcher.tsx

echo ""
echo "=== Search for how /channels/new is created - could be a modal or dynamic route ==="
rg "channels.*new|createChannelModal|CreateChannelForm" packages/dashboard/src -i -A 2 | head -60

Repository: vendurehq/vendure

Length of output: 2389


🏁 Script executed:

#!/bin/bash
# Check if there's a create channel page or modal component
echo "=== Search for create channel related files ==="
find packages/dashboard/src -type f -name "*create*channel*" -o -name "*channel*create*" | grep -v node_modules

echo ""
echo "=== Look at the full channels.tsx file ==="
wc -l packages/dashboard/src/app/routes/_authenticated/_channels/channels.tsx

echo ""
echo "=== Search for PermissionGuard in channel routes ==="
grep -r "PermissionGuard" packages/dashboard/src/app/routes/_authenticated/_channels/ 2>/dev/null

Repository: vendurehq/vendure

Length of output: 1090


🏁 Script executed:

#!/bin/bash
# Read the channels_.$id.tsx file to check permission handling
cat packages/dashboard/src/app/routes/_authenticated/_channels/channels_.$id.tsx

Repository: vendurehq/vendure

Length of output: 166


🏁 Script executed:

#!/bin/bash
# Find and read the channels detail file
find packages/dashboard/src/app/routes/_authenticated/_channels -name "channels_*" -type f

Repository: vendurehq/vendure

Length of output: 137


🏁 Script executed:

#!/bin/bash
# Read the channels detail page file with proper escaping
file=$(find packages/dashboard/src/app/routes/_authenticated/_channels -name "channels_*" -type f)
cat "$file"

Repository: vendurehq/vendure

Length of output: 11778


🏁 Script executed:

#!/bin/bash
# Check what NEW_ENTITY_PATH is
rg "NEW_ENTITY_PATH" packages/dashboard/src -A 2 | head -20

Repository: vendurehq/vendure

Length of output: 1803


🏁 Script executed:

#!/bin/bash
# Check the detail-page-route-loader to see if it includes permission checks
echo "=== Checking detail-page-route-loader.tsx ==="
cat packages/dashboard/src/lib/framework/page/detail-page-route-loader.tsx

Repository: vendurehq/vendure

Length of output: 2617


🏁 Script executed:

#!/bin/bash
# Check if there's any documentation about permission hierarchy or if UpdateChannel covers CreateChannel
echo "=== Searching for permission definitions or documentation ==="
find packages -name "*.ts" -o -name "*.tsx" | xargs grep -l "CreateChannel\|UpdateChannel" | grep -v node_modules | head -20

echo ""
echo "=== Check for permission definitions in server ==="
find packages -path "*/server/*" -name "*permission*" -o -name "*auth*" | grep -v node_modules | head -20

Repository: vendurehq/vendure

Length of output: 2356


🏁 Script executed:

#!/bin/bash
# Check the useDetailPage hook to understand permission logic
echo "=== Checking useDetailPage for mutation permission handling ==="
rg "CreateChannel|UpdateChannel|createDocument|updateDocument" packages/dashboard/src/lib/framework/page/use-detail-page.tsx -B 2 -A 2

Repository: vendurehq/vendure

Length of output: 243


🏁 Script executed:

#!/bin/bash
# Find the use-detail-page file
find packages/dashboard/src -name "*use-detail-page*" -type f

echo ""
echo "=== Read the file ==="
file=$(find packages/dashboard/src -name "*use-detail-page*" -type f)
cat "$file" | head -150

Repository: vendurehq/vendure

Length of output: 5076


🏁 Script executed:

#!/bin/bash
# Search for where the create/update mutations are actually executed and if they have permission checks
echo "=== Search for mutation execution in detail pages ==="
rg "useMutation|createChannelDocument|updateChannelDocument" packages/dashboard/src/app/routes/_authenticated/_channels/ -B 3 -A 3

Repository: vendurehq/vendure

Length of output: 3393


🏁 Script executed:

#!/bin/bash
# Check the full use-detail-page.ts file to see where the mutation is executed
cat packages/dashboard/src/lib/framework/page/use-detail-page.ts | tail -200

Repository: vendurehq/vendure

Length of output: 7001


🏁 Script executed:

#!/bin/bash
# Check if the route loader has any permission validation
echo "=== Check for route guards or permission checks in route configuration ==="
grep -A 20 "createFileRoute.*_channels/channels_" packages/dashboard/src/app/routes/_authenticated/_channels/channels_.$id.tsx | head -30

echo ""
echo "=== Check if there's a higher-level authentication/permission middleware ==="
find packages/dashboard/src -name "*auth*" -o -name "*guard*" -o -name "*middleware*" | grep -v node_modules | head -20

echo ""
echo "=== Look for BeforeLoad or similar route-level protection ==="
rg "beforeLoad|beforeNavigate|onBeforeLoad" packages/dashboard/src/app/routes -B 2 -A 5 | head -60

Repository: vendurehq/vendure

Length of output: 2055


🏁 Script executed:

#!/bin/bash
# Check the PermissionGuard implementation to understand how it works
echo "=== Check PermissionGuard implementation ==="
cat packages/dashboard/src/lib/components/shared/permission-guard.tsx

echo ""
echo "=== Check if there's backend permission enforcement ==="
rg "CreateChannel.*permission|permission.*CreateChannel" packages/core -A 3 -B 3 | head -50

Repository: vendurehq/vendure

Length of output: 1534


🏁 Script executed:

#!/bin/bash
# Look more closely at the permission used in the button in channels_.$id.tsx
echo "=== Check the exact permission used in the Create/Update button ==="
sed -n '130,145p' packages/dashboard/src/app/routes/_authenticated/_channels/channels_.$id.tsx

echo ""
echo "=== Verify if CreateChannel should be used instead ==="
rg "CreateChannel.*permission|requires.*CreateChannel" packages/dashboard/src -B 2 -A 2 | head -40

Repository: vendurehq/vendure

Length of output: 1496


🏁 Script executed:

#!/bin/bash
# Find the exact file path and read it
find packages/dashboard/src/app/routes/_authenticated/_channels -name "channels_*" -type f

echo ""
echo "=== Read lines around the button in the detail page ==="
file=$(find packages/dashboard/src/app/routes/_authenticated/_channels -name "channels_*" -type f)
sed -n '130,150p' "$file"

Repository: vendurehq/vendure

Length of output: 1194


🏁 Script executed:

#!/bin/bash
# Find the PermissionGuard line with UpdateChannel in the detail page
file=$(find packages/dashboard/src/app/routes/_authenticated/_channels -name "channels_*" -type f)
grep -n "PermissionGuard" "$file"

echo ""
echo "=== Read the exact section with the submit button ==="
grep -n "PermissionGuard\|UpdateChannel\|submit" "$file" -B 2 -A 5

Repository: vendurehq/vendure

Length of output: 2333


🏁 Script executed:

#!/bin/bash
# Verify permission hierarchy - check if UpdateChannel includes CreateChannel or if they're separate
echo "=== Search for permission definitions and hierarchy ==="
rg "CreateChannel|UpdateChannel" packages/core/src -B 2 -A 2 | grep -i "permission\|enum\|const" | head -30

Repository: vendurehq/vendure

Length of output: 941


🏁 Script executed:

#!/bin/bash
# Verify the exact backend mutation permissions
echo "=== Check backend channel resolver mutations ==="
rg "createChannel|updateChannel" packages/core/src/api/resolvers/admin/channel.resolver.ts -B 5 -A 10 | head -80

Repository: vendurehq/vendure

Length of output: 1247


Fix permission check on channel creation form.

The submit button on the channel detail page uses UpdateChannel permission for both create and update operations. For new channel creation, it should check CreateChannel permission to match the backend mutation requirements and the UI checks in the list page.

Currently, a user with only CreateChannel permission can access /channels/new but the submit button will be hidden because it checks for UpdateChannel instead. The backend mutation correctly requires CreateChannel, creating a permission mismatch between frontend and backend.

Update line 120 in packages/dashboard/src/app/routes/_authenticated/_channels/channels_.$id.tsx to conditionally check CreateChannel when creating a new entity:

<PermissionGuard requires={creatingNewEntity ? ['CreateChannel'] : ['UpdateChannel']}>
🤖 Prompt for AI Agents
In @packages/dashboard/src/lib/components/layout/channel-switcher.tsx around
lines 198 - 210, The submit button permission check uses a fixed
['UpdateChannel'] which hides the button when creating a new channel; update the
PermissionGuard around the submit action to use a conditional requires prop that
uses ['CreateChannel'] when creatingNewEntity is true and ['UpdateChannel']
otherwise (i.e., change the requires prop on PermissionGuard to depend on
creatingNewEntity). Ensure this logic is applied where PermissionGuard is used
for the channel form submit button and aligns with the backend mutation
permission.

@michaelbromley
Copy link
Member

Thanks for the quick response - could you just fix that merge conflict? 🙏

…nnel permission

  Wrap the "Add channel" menu item in PermissionGuard to only show it
  to users with the CreateChannel permission.

  Fixes vendurehq#4056
@niko91i niko91i force-pushed the fix/hide-add-channel-without-permission branch from b7af4f5 to 40b91e4 Compare January 7, 2026 15:42
@michaelbromley michaelbromley merged commit 84d7733 into vendurehq:master Jan 7, 2026
28 of 33 checks passed
@michaelbromley
Copy link
Member

Thank you!

@sonarqubecloud
Copy link

sonarqubecloud bot commented Jan 7, 2026

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Dashboard: Channel selector menu and new channel creation page being shown to seller admin without any channel permissions

2 participants