-
Notifications
You must be signed in to change notification settings - Fork 14
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: userroles and permissions #123
Changes from 2 commits
623c059
ce75484
4f4a7ac
4deec30
4e8d9ab
0b4d687
e57265d
4ffe185
9c151bf
a259950
e4503a1
09f0c3c
a99caa5
59127f1
c37f0df
dba0c25
20b5ae1
d8194d8
643d7f1
078c77c
a882c68
191421f
fd00867
64c9d12
7b803da
fdf6779
aa29100
35177d8
ed399c8
0bbebd2
4499f77
9b02eb7
3e84cb9
8196a87
481d768
d4f1e8e
e0e894d
30fb351
aaa9619
60f1db0
8c59217
f49e3e2
66f63b4
d0f3dcf
206e43d
ca58cfd
e161626
27cc554
488b212
0628fbc
065a41b
ac54b18
adea6d8
00b015f
bb9642e
1e3e97d
7c262d4
242b57a
025d2f7
f11d5dd
a6d640b
0c18fa8
a306aef
8f67045
d3cc14b
dc5ad97
eeeb122
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
import { useState } from "react"; | ||
import { ReactComponent as ArrowDown } from "../../../assets/arrow-down.svg"; | ||
|
||
import "./select.scss"; | ||
|
||
type SelectProps = { | ||
options: { value: string; name: string }[]; | ||
selectedOption: string; | ||
onOptionSelect: (value: string) => void; | ||
}; | ||
export default function Select({ onOptionSelect, options, selectedOption }: SelectProps) { | ||
const [showOptions, setShowOptions] = useState(false); | ||
return ( | ||
<div | ||
className="select-container" | ||
onMouseLeave={() => setShowOptions(false)} | ||
onMouseEnter={() => setShowOptions(true)}> | ||
<div className="select-action"> | ||
{selectedOption}{" "} | ||
<ArrowDown | ||
color="#000" | ||
style={{ rotate: showOptions ? "180deg" : undefined }} | ||
/> | ||
</div> | ||
{showOptions ? ( | ||
<div className="select-dropdown-wrapper"> | ||
<div className="select-dropdown"> | ||
{options.map((option) => { | ||
return ( | ||
<div | ||
className="select-item" | ||
key={option.value} | ||
onClick={(e) => { | ||
e.stopPropagation(); | ||
onOptionSelect(option.value); | ||
setShowOptions(false); | ||
}}> | ||
{option.name} | ||
</div> | ||
); | ||
})} | ||
</div> | ||
</div> | ||
) : null} | ||
</div> | ||
); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
.select-container { | ||
position: relative; | ||
cursor: pointer; | ||
|
||
.select-action { | ||
display: flex; | ||
width: 210px; | ||
height: 36px; | ||
padding: 9px 13px; | ||
justify-content: space-between; | ||
align-items: center; | ||
gap: 10px; | ||
flex-shrink: 0; | ||
|
||
border-radius: 6px; | ||
border: 1px solid #e5e5e5; | ||
background: #fff; | ||
|
||
color: #222; | ||
font-size: 14px; | ||
font-style: normal; | ||
font-weight: 400; | ||
line-height: normal; | ||
} | ||
.select-dropdown-wrapper { | ||
padding-top: 5px; | ||
z-index: 5; | ||
position: absolute; | ||
width: 100%; | ||
|
||
.select-dropdown { | ||
background: #fff; | ||
border-radius: 6px; | ||
background: #fff; | ||
box-shadow: 0px 0px 3px 0px rgba(0, 0, 0, 0.16); | ||
|
||
.select-item { | ||
cursor: pointer; | ||
padding: 12px; | ||
color: #222; | ||
font-size: 14px; | ||
font-style: normal; | ||
font-weight: 400; | ||
line-height: normal; | ||
|
||
&:hover { | ||
background: #f0f0f0; | ||
width: 100%; | ||
} | ||
} | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -18,8 +18,8 @@ import { Tenant } from "../../../api/tenants/list"; | |
import { GetUserInfoResult, UpdateUserInformationResponse, useUserService } from "../../../api/user"; | ||
import useMetadataService from "../../../api/user/metadata"; | ||
import useSessionsForUserService from "../../../api/user/sessions"; | ||
import { useUserRolesService } from "../../../api/userroles/user/roles"; | ||
import { getImageUrl, getRecipeNameFromid } from "../../../utils"; | ||
import { UserRolesResponse, useUserRolesService } from "../../../api/userroles/user/roles"; | ||
import { getImageUrl, getRecipeNameFromid, getSelectedTenantId } from "../../../utils"; | ||
import { getTenantsObjectsForIds } from "../../../utils/user"; | ||
import { PopupContentContext } from "../../contexts/PopupContentContext"; | ||
import { User, UserRecipeType } from "../../pages/usersList/types"; | ||
|
@@ -56,8 +56,8 @@ export const UserDetail: React.FC<UserDetailProps> = (props) => { | |
const [userMetaData, setUserMetaData] = useState<string | undefined>(undefined); | ||
rishabhpoddar marked this conversation as resolved.
Show resolved
Hide resolved
|
||
const [shouldShowLoadingOverlay, setShowLoadingOverlay] = useState<boolean>(false); | ||
const [isLoading, setIsLoading] = useState(false); | ||
const [userRoles, setUserRoles] = useState<string[] | undefined>(undefined); | ||
const [isUserRolesFeatureEnabled, setIsUserRolesFeatureEnabled] = useState<boolean | undefined>(undefined); | ||
const [userRolesData, setUserRolesData] = useState<UserRolesResponse | undefined>(undefined); | ||
const [currentlySelectedTenantId, setCurrentlySelectedTenantId] = useState(getSelectedTenantId() ?? "public"); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. the default should be based on the tenant that the user belongs to - not from what comes from the user listing page. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If the user belongs to the public tenant, show that, else whatever is the first item in the list of their tenants. |
||
|
||
const { getUser, updateUserInformation } = useUserService(); | ||
const { getUserMetaData } = useMetadataService(); | ||
|
@@ -155,16 +155,10 @@ export const UserDetail: React.FC<UserDetailProps> = (props) => { | |
}, []); | ||
|
||
async function fetchUserRoles() { | ||
const response = await getRolesForUser(user); | ||
setUserRolesData(undefined); | ||
const response = await getRolesForUser(user, currentlySelectedTenantId); | ||
if (response !== undefined) { | ||
if (response.status === "OK") { | ||
setUserRoles(response.roles); | ||
setIsUserRolesFeatureEnabled(true); | ||
} | ||
|
||
if (response.status === "FEATURE_NOT_ENABLED_ERROR") { | ||
setIsUserRolesFeatureEnabled(false); | ||
} | ||
setUserRolesData(response); | ||
} else { | ||
showToast({ | ||
iconImage: getImageUrl("form-field-error-icon.svg"), | ||
|
@@ -204,7 +198,11 @@ export const UserDetail: React.FC<UserDetailProps> = (props) => { | |
void fetchData(); | ||
}, []); | ||
|
||
if (userDetail === undefined || isLoading) { | ||
useEffect(() => { | ||
void fetchUserRoles(); | ||
}, [currentlySelectedTenantId]); | ||
|
||
if (userDetail === undefined || userRolesData === undefined || isLoading) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. remove There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Have the loading thing just in the user details section. |
||
return ( | ||
<div className="user-detail-page-loader"> | ||
<div className="loader"></div> | ||
|
@@ -280,8 +278,13 @@ export const UserDetail: React.FC<UserDetailProps> = (props) => { | |
<UserDetailInfoGrid {...props} /> | ||
|
||
<UserRolesList | ||
isFeatureEnabled={isUserRolesFeatureEnabled} | ||
roles={userRoles} | ||
key={currentlySelectedTenantId} | ||
currentlySelectedTenantId={currentlySelectedTenantId} | ||
onTenantIdChange={(tenantId: string) => { | ||
setCurrentlySelectedTenantId(tenantId); | ||
}} | ||
isFeatureEnabled={userRolesData.status !== "FEATURE_NOT_ENABLED_ERROR"} | ||
roles={userRolesData.status === "OK" ? userRolesData.roles : []} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. for isFeatureEnabled and roles, we can't just assume true and [] in case userRolesData is undefined. |
||
userId={user} | ||
/> | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use the browser selector and style that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I added a click action to the select component to handle mobile and tablet devices. as styling native select element is really a overhead.