Skip to content

Commit 9044d57

Browse files
committed
feat: create permission component
Signed-off-by: codeSafari10 <codeSafari10@gmail.com>
1 parent 8930306 commit 9044d57

2 files changed

Lines changed: 105 additions & 0 deletions

File tree

src/custom/index.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,3 +122,4 @@ export type {
122122
};
123123

124124
export * from './Dialog';
125+
export * from './permissions';

src/custom/permissions.tsx

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
// import { CAN, getCapabilitiesRegistry, getMesheryEventBus } from '@/globals/mesherySdk';
2+
import React from 'react';
3+
import { EventBus } from '../actors/eventBus';
4+
5+
interface Key {
6+
subject: string;
7+
action: string;
8+
}
9+
10+
type InvertAction = 'disable' | 'hide';
11+
12+
export type MissingPermissionReason = {
13+
type: 'MISSING_PERMISSION';
14+
data: {
15+
keyId: string;
16+
};
17+
};
18+
19+
export type MissingCapabilityReason = {
20+
type: 'MISSING_CAPABILITY';
21+
data: {
22+
capabilityId: string;
23+
};
24+
};
25+
26+
export type ReasonEvent = MissingPermissionReason | MissingCapabilityReason;
27+
28+
interface HasKeyProps<ReasonEvent> {
29+
Key?: Key;
30+
predicate?: (capabilitiesRegistry: unknown) => [boolean, ReasonEvent]; // returns a boolean and an event if the user does not have the permission
31+
children: React.ReactNode;
32+
allowClick?: boolean;
33+
invert_action?: InvertAction[];
34+
}
35+
36+
// returns the children if the user has the permission to view the component or if a key is not provided
37+
// if the user does not have the permission to view the component, it will return null or a disabled version of the component specified by the invert_action prop
38+
export const createCanShow = (
39+
getCapabilitiesRegistry = () => {},
40+
CAN: (action: string, subject: string) => boolean,
41+
eventBus: () => EventBus<ReasonEvent>
42+
) => {
43+
return ({ Key, children, predicate, invert_action = ['disable'] }: HasKeyProps<ReasonEvent>) => {
44+
if (!children) {
45+
return null;
46+
}
47+
48+
const hasKey = Key?.subject ? CAN(Key?.action, Key?.subject) : true;
49+
const predicateRes = predicate && predicate(getCapabilitiesRegistry());
50+
51+
//WARNING: remove the false from the below line to enable the feature
52+
const can = predicateRes ? predicateRes[0] && hasKey && false : hasKey && false;
53+
54+
const reason = predicateRes?.[1] || {
55+
type: 'MISSING_PERMISSION',
56+
data: {
57+
keyId: Key?.action as string
58+
}
59+
};
60+
61+
if (can) {
62+
return <>{children}</>;
63+
}
64+
65+
if (invert_action.includes('hide')) {
66+
return null;
67+
}
68+
69+
const isClickable = children && (children as React.ReactElement).props.onClick;
70+
const pointerEvents = isClickable ? 'auto' : 'none';
71+
72+
const onClick = isClickable
73+
? () => {
74+
console.log('cant perform action : reason', reason);
75+
const mesheryEventBus = eventBus();
76+
mesheryEventBus.publish(reason);
77+
}
78+
: () => {};
79+
80+
const opacity = invert_action.includes('disable') ? 0.5 : 1;
81+
82+
return (
83+
<div
84+
style={{
85+
cursor: 'pointer',
86+
pointerEvents,
87+
opacity: opacity
88+
}}
89+
>
90+
{React.cloneElement(children as React.ReactElement, {
91+
style: {
92+
...((children as React.ReactElement).props.style as React.CSSProperties),
93+
cursor: 'pointer',
94+
pointerEvents,
95+
opacity: opacity
96+
},
97+
onClick: onClick
98+
})}
99+
</div>
100+
);
101+
102+
return null;
103+
};
104+
};

0 commit comments

Comments
 (0)