Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 0 additions & 39 deletions frontend/common/hooks/useFeatureListWithApiKey.ts

This file was deleted.

84 changes: 0 additions & 84 deletions frontend/common/hooks/usePageTracking.ts

This file was deleted.

58 changes: 0 additions & 58 deletions frontend/common/hooks/useProjectEnvironments.ts

This file was deleted.

138 changes: 10 additions & 128 deletions frontend/common/providers/Permission.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,51 +4,15 @@ import { PermissionLevel } from 'common/types/requests'
import AccountStore from 'common/stores/account-store'
import intersection from 'lodash/intersection'
import { cloneDeep } from 'lodash'
import Utils from 'common/utils/utils'
import Constants from 'common/constants'

/**
* Props for the Permission component
*
* @property {number | string} id - The ID of the resource (projectId, organisationId, environmentId, etc.)
* @property {string} permission - The permission key to check (e.g., 'CREATE_FEATURE', 'UPDATE_FEATURE')
* @property {PermissionLevel} level - The permission level ('project', 'organisation', 'environment')
* @property {number[]} [tags] - Optional tag IDs for tag-based permission checking
* @property {ReactNode | ((data: { permission: boolean; isLoading: boolean }) => ReactNode)} children - Content to render or render function
* @property {ReactNode} [fallback] - Optional content to render when permission is denied
* @property {string} [permissionName] - Optional custom permission name for tooltip display
* @property {boolean} [showTooltip=false] - Whether to show a tooltip when permission is denied
*/
type PermissionType = {
id: number | string
id: any
permission: string
tags?: number[]
level: PermissionLevel
children:
| ReactNode
| ((data: { permission: boolean; isLoading: boolean }) => ReactNode)
fallback?: ReactNode
permissionName?: string
showTooltip?: boolean
children: (data: { permission: boolean; isLoading: boolean }) => ReactNode
}

/**
* Hook to check if the current user has a specific permission
*
* Fetches permission data and checks if the user has the requested permission.
* Supports tag-based permissions where additional permissions can be granted
* based on tag intersection.
*
* @param {Object} params - The permission check parameters
* @param {number | string} params.id - The resource ID to check permissions for
* @param {PermissionLevel} params.level - The permission level to check at
* @param {string} params.permission - The permission key to check
* @param {number[]} [params.tags] - Optional tag IDs for tag-based permission checking
* @returns {Object} Object containing permission status and loading state
* @returns {boolean} returns.isLoading - Whether the permission data is still loading
* @returns {boolean} returns.isSuccess - Whether the permission data was fetched successfully
* @returns {boolean} returns.permission - Whether the user has the requested permission
*/
export const useHasPermission = ({
id,
level,
Expand Down Expand Up @@ -81,68 +45,11 @@ export const useHasPermission = ({
}
}

/**
* Permission component for conditional rendering based on user permissions
*
* This component checks if the current user has a specific permission and conditionally
* renders its children. It supports multiple rendering patterns:
*
* @example
* // Basic usage with simple children
* <Permission level="project" permission="CREATE_FEATURE" id={projectId}>
* <Button>Create Feature</Button>
* </Permission>
*
* @example
* // Using render function to access permission state
* <Permission level="project" permission="CREATE_FEATURE" id={projectId}>
* {({ permission, isLoading }) => (
* <Button disabled={!permission || isLoading}>Create Feature</Button>
* )}
* </Permission>
*
* @example
* // With tooltip on permission denial
* <Permission
* level="project"
* permission="CREATE_FEATURE"
* id={projectId}
* showTooltip
* permissionName="Create Features"
* >
* <Button>Create Feature</Button>
* </Permission>
*
* @example
* // With fallback content
* <Permission
* level="project"
* permission="DELETE_FEATURE"
* id={projectId}
* fallback={<Text>You don't have permission to delete features</Text>}
* >
* <Button>Delete Feature</Button>
* </Permission>
*
* @example
* // With tag-based permissions
* <Permission
* level="project"
* permission="UPDATE_FEATURE"
* id={projectId}
* tags={[tagId1, tagId2]}
* >
* <Button>Update Feature</Button>
* </Permission>
*/
const Permission: FC<PermissionType> = ({
children,
fallback,
id,
level,
permission,
permissionName,
showTooltip = false,
tags,
}) => {
const { isLoading, permission: hasPermission } = useHasPermission({
Expand All @@ -151,39 +58,14 @@ const Permission: FC<PermissionType> = ({
permission,
tags,
})

const finalPermission = hasPermission || AccountStore.isAdmin()

if (typeof children === 'function') {
const renderedChildren = children({
isLoading,
permission: finalPermission,
})

if (finalPermission || !showTooltip) {
return <>{renderedChildren || null}</>
}

return Utils.renderWithPermission(
finalPermission,
permissionName || Constants.projectPermissions(permission),
renderedChildren,
)
}

if (finalPermission) {
return <>{children}</>
}

if (showTooltip) {
return Utils.renderWithPermission(
finalPermission,
permissionName || Constants.projectPermissions(permission),
children,
)
}

return <>{fallback || null}</>
return (
<>
{children({
isLoading,
permission: hasPermission || AccountStore.isAdmin(),
}) || null}
</>
)
}

export default Permission
Loading
Loading