-
Notifications
You must be signed in to change notification settings - Fork 1.5k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: client side access control checks (#27635)
Co-authored-by: github-actions <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Michael Matloka <[email protected]>
- Loading branch information
Showing
23 changed files
with
431 additions
and
100 deletions.
There are no files selected for viewing
Binary file modified
BIN
-772 Bytes
(100%)
frontend/__snapshots__/scenes-app-feature-flags--edit-feature-flag--light.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified
BIN
-488 Bytes
(100%)
...snapshots__/scenes-app-feature-flags--edit-multi-variate-feature-flag--dark.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified
BIN
+106 Bytes
(100%)
frontend/__snapshots__/scenes-app-insights--trends-area--light--webkit.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified
BIN
+97 Bytes
(100%)
frontend/__snapshots__/scenes-app-insights--trends-bar--light--webkit.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified
BIN
+152 Bytes
(100%)
frontend/__snapshots__/scenes-app-insights--trends-pie--light--webkit.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified
BIN
+175 Bytes
(100%)
frontend/__snapshots__/scenes-app-insights--trends-world-map--light--webkit.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
import { AccessControlResourceType } from '~/types' | ||
|
||
type AccessControlLevelNone = 'none' | ||
type AccessControlLevelMember = AccessControlLevelNone | 'member' | 'admin' | ||
type AccessControlLevelResource = AccessControlLevelNone | 'viewer' | 'editor' | ||
type AccessControlLevel = AccessControlLevelMember | AccessControlLevelResource | ||
|
||
interface AccessControlActionProps { | ||
children: (props: { disabled: boolean; disabledReason: string | null }) => React.ReactElement | ||
userAccessLevel?: AccessControlLevel | ||
minAccessLevel: AccessControlLevel | ||
resourceType: AccessControlResourceType | ||
} | ||
|
||
const orderedAccessLevels = (resourceType: AccessControlResourceType): AccessControlLevel[] => { | ||
if (resourceType === AccessControlResourceType.Project || resourceType === AccessControlResourceType.Organization) { | ||
return ['none', 'member', 'admin'] | ||
} | ||
return ['none', 'viewer', 'editor'] | ||
} | ||
|
||
const resourceTypeToString = (resourceType: AccessControlResourceType): string => { | ||
if (resourceType === AccessControlResourceType.FeatureFlag) { | ||
return 'feature flag' | ||
} | ||
|
||
// The rest are single words | ||
return resourceType | ||
} | ||
|
||
export const accessLevelSatisfied = ( | ||
resourceType: AccessControlResourceType, | ||
currentLevel: AccessControlLevel, | ||
requiredLevel: AccessControlLevel | ||
): boolean => { | ||
const levels = orderedAccessLevels(resourceType) | ||
return levels.indexOf(currentLevel) >= levels.indexOf(requiredLevel) | ||
} | ||
|
||
// This is a wrapper around a component that checks if the user has access to the resource | ||
// and if not, it disables the component and shows a reason why | ||
export const AccessControlAction = ({ | ||
children, | ||
userAccessLevel, | ||
minAccessLevel, | ||
resourceType = AccessControlResourceType.Project, | ||
}: AccessControlActionProps): JSX.Element => { | ||
const hasAccess = userAccessLevel ? accessLevelSatisfied(resourceType, userAccessLevel, minAccessLevel) : true | ||
const disabledReason = !hasAccess | ||
? `You don't have sufficient permissions for this ${resourceTypeToString( | ||
resourceType | ||
)}. Your access level (${userAccessLevel}) doesn't meet the required level (${minAccessLevel}).` | ||
: null | ||
|
||
return children({ | ||
disabled: !hasAccess, | ||
disabledReason, | ||
}) | ||
} |
32 changes: 32 additions & 0 deletions
32
frontend/src/lib/components/AccessControlledLemonButton.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
import { LemonButton, LemonButtonProps } from 'lib/lemon-ui/LemonButton' | ||
|
||
import { AccessControlResourceType, WithAccessControl } from '../../types' | ||
import { AccessControlAction } from './AccessControlAction' | ||
|
||
export type AccessControlledLemonButtonProps = LemonButtonProps & { | ||
userAccessLevel?: WithAccessControl['user_access_level'] | ||
minAccessLevel: WithAccessControl['user_access_level'] | ||
resourceType: AccessControlResourceType | ||
} | ||
|
||
export const AccessControlledLemonButton = ({ | ||
userAccessLevel, | ||
minAccessLevel, | ||
resourceType, | ||
children, | ||
...props | ||
}: AccessControlledLemonButtonProps): JSX.Element => { | ||
return ( | ||
<AccessControlAction | ||
userAccessLevel={userAccessLevel} | ||
minAccessLevel={minAccessLevel} | ||
resourceType={resourceType} | ||
> | ||
{({ disabledReason: accessControlDisabledReason }) => ( | ||
<LemonButton {...props} disabledReason={accessControlDisabledReason || props.disabledReason}> | ||
{children} | ||
</LemonButton> | ||
)} | ||
</AccessControlAction> | ||
) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.