mirror of
https://github.com/langgenius/dify.git
synced 2026-08-30 17:11:50 +08:00
feat: hide skill_entry when use has no skill.view permission (#41429)
This commit is contained in:
@@ -1068,11 +1068,6 @@
|
||||
"count": 2
|
||||
}
|
||||
},
|
||||
"web/app/components/base/icons/src/public/billing/index.ts": {
|
||||
"no-barrel-files/no-barrel-files": {
|
||||
"count": 4
|
||||
}
|
||||
},
|
||||
"web/app/components/base/icons/src/public/common/index.ts": {
|
||||
"no-barrel-files/no-barrel-files": {
|
||||
"count": 5
|
||||
@@ -1767,11 +1762,6 @@
|
||||
"count": 3
|
||||
}
|
||||
},
|
||||
"web/app/components/billing/pricing/assets/index.tsx": {
|
||||
"no-barrel-files/no-barrel-files": {
|
||||
"count": 12
|
||||
}
|
||||
},
|
||||
"web/app/components/datasets/chunk.tsx": {
|
||||
"jsx-a11y/label-has-associated-control": {
|
||||
"count": 2
|
||||
@@ -5408,4 +5398,4 @@
|
||||
"count": 2
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -465,6 +465,7 @@ const ownerWorkspacePermissionKeys = [
|
||||
'tool.manage',
|
||||
'mcp.manage',
|
||||
'agent.manage',
|
||||
'skill.view',
|
||||
]
|
||||
|
||||
const datasetOperatorWorkspacePermissionKeys = [
|
||||
@@ -784,6 +785,17 @@ describe('MainNav', () => {
|
||||
expect(screen.queryByRole('link', { name: /common.mainNav.skills/ })).not.toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('hides the skills entry when the user lacks skill.view', () => {
|
||||
mockConsoleState.current = {
|
||||
...consoleState,
|
||||
workspacePermissionKeys: ownerWorkspacePermissionKeys.filter((key) => key !== 'skill.view'),
|
||||
}
|
||||
|
||||
renderMainNav()
|
||||
|
||||
expect(screen.queryByRole('link', { name: /common.mainNav.skills/ })).not.toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('orders the Step-by-step Tour before the account and help actions', async () => {
|
||||
localStorage.setItem(STEP_BY_STEP_TOUR_SHELL_MODE_STORAGE_KEY, 'collapsed')
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@ import { isCurrentWorkspaceDatasetOperatorAtom } from '@/context/workspace-state
|
||||
import { userProfileQueryOptions } from '@/features/account-profile/client'
|
||||
import { isAgentV2Enabled } from '@/features/agent-v2/feature-flag'
|
||||
import { useCanManageAgents } from '@/features/agent-v2/permissions'
|
||||
import { useCanViewSkills } from '@/features/skills/permissions'
|
||||
import { systemFeaturesQueryOptions } from '@/features/system-features/client'
|
||||
import dynamic from '@/next/dynamic'
|
||||
import Link from '@/next/link'
|
||||
@@ -39,6 +40,7 @@ export function MainNav({ className }: MainNavProps) {
|
||||
})
|
||||
const agentV2Enabled = isAgentV2Enabled()
|
||||
const canManageAgents = useCanManageAgents()
|
||||
const canViewSkills = useCanViewSkills()
|
||||
const enableSkill = useProviderContextSelector((state) => state.enableSkill)
|
||||
const showEnvTag = currentEnv === 'TESTING' || currentEnv === 'DEVELOPMENT'
|
||||
const helpMenuTriggerRef = useRef<HTMLButtonElement>(null)
|
||||
@@ -49,6 +51,7 @@ export function MainNav({ className }: MainNavProps) {
|
||||
isMainNavRouteVisible(route, {
|
||||
agentV2Enabled,
|
||||
canManageAgents,
|
||||
canViewSkills,
|
||||
isCurrentWorkspaceDatasetOperator,
|
||||
marketplaceEnabled: systemFeatures.enable_marketplace,
|
||||
skillEnabled: enableSkill,
|
||||
@@ -63,6 +66,7 @@ export function MainNav({ className }: MainNavProps) {
|
||||
[
|
||||
agentV2Enabled,
|
||||
canManageAgents,
|
||||
canViewSkills,
|
||||
enableSkill,
|
||||
isCurrentWorkspaceDatasetOperator,
|
||||
systemFeatures.enable_marketplace,
|
||||
|
||||
@@ -18,6 +18,7 @@ export type MainNavRouteConfig = {
|
||||
export type MainNavRouteVisibilityOptions = {
|
||||
agentV2Enabled: boolean
|
||||
canManageAgents: boolean
|
||||
canViewSkills: boolean
|
||||
isCurrentWorkspaceDatasetOperator: boolean
|
||||
marketplaceEnabled: boolean
|
||||
skillEnabled: boolean
|
||||
@@ -31,7 +32,7 @@ export type DetailSidebarVisibilityOptions = Pick<
|
||||
const VISIBLE_TO_ALL: MainNavRouteVisibility = () => true
|
||||
const CAN_MANAGE_AGENTS: MainNavRouteVisibility = (options) => options.canManageAgents
|
||||
const SKILL_ENABLED_FOR_WORKSPACE: MainNavRouteVisibility = (options) =>
|
||||
options.skillEnabled && !options.isCurrentWorkspaceDatasetOperator
|
||||
options.skillEnabled && options.canViewSkills && !options.isCurrentWorkspaceDatasetOperator
|
||||
|
||||
function isPathUnderRoute(pathname: string, route: string) {
|
||||
return pathname === route || pathname.startsWith(`${route}/`)
|
||||
|
||||
@@ -3,15 +3,23 @@ import { workspacePermissionKeysAtom } from '@/context/permission-state'
|
||||
import { hasPermission } from '@/utils/permission'
|
||||
|
||||
const SkillPermission = {
|
||||
View: 'skill.view',
|
||||
Edit: 'skill.edit',
|
||||
Publish: 'skill.publish',
|
||||
Delete: 'skill.delete',
|
||||
} as const
|
||||
|
||||
export function useCanViewSkills() {
|
||||
const permissionKeys = useAtomValue(workspacePermissionKeysAtom)
|
||||
|
||||
return hasPermission(permissionKeys, SkillPermission.View)
|
||||
}
|
||||
|
||||
export function useSkillPermissions() {
|
||||
const permissionKeys = useAtomValue(workspacePermissionKeysAtom)
|
||||
|
||||
return {
|
||||
canView: hasPermission(permissionKeys, SkillPermission.View),
|
||||
canEdit: hasPermission(permissionKeys, SkillPermission.Edit),
|
||||
canPublish: hasPermission(permissionKeys, SkillPermission.Publish),
|
||||
canDelete: hasPermission(permissionKeys, SkillPermission.Delete),
|
||||
|
||||
Reference in New Issue
Block a user