Skip to content

Commit

Permalink
Add friendly name to list group members response (#8413)
Browse files Browse the repository at this point in the history
  • Loading branch information
idanovo authored Dec 17, 2024
1 parent fb5648f commit e74938c
Show file tree
Hide file tree
Showing 9 changed files with 57 additions and 23 deletions.
1 change: 1 addition & 0 deletions contrib/auth/acl/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,7 @@ func (c *Controller) ListGroupMembers(w http.ResponseWriter, r *http.Request, gr
Username: u.Username,
CreationDate: u.CreatedAt.Unix(),
Email: u.Email,
FriendlyName: u.FriendlyName,
})
}
writeResponse(w, http.StatusOK, response)
Expand Down
1 change: 1 addition & 0 deletions pkg/api/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -1112,6 +1112,7 @@ func (c *Controller) ListGroupMembers(w http.ResponseWriter, r *http.Request, gr
Id: u.Username,
Email: u.Email,
CreationDate: u.CreatedAt.Unix(),
FriendlyName: u.FriendlyName,
})
}
writeResponse(w, r, http.StatusOK, response)
Expand Down
15 changes: 4 additions & 11 deletions webui/src/lib/components/auth/forms.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,8 @@ import {SearchIcon} from "@primer/octicons-react";
import {useAPI} from "../../hooks/api";
import {Checkbox, DataTable, DebouncedFormControl, AlertError, Loading} from "../controls";

const resolveEntityDisplayName = (ent) => {
// for users
if (ent?.email?.length) return ent.email;
// for groups
if (ent?.name?.length) return ent.name;
return ent.id;
}

export const AttachModal = ({ show, searchFn, onAttach, onHide, addText = "Add",

export const AttachModal = ({ show, searchFn, resolveEntityFn = (ent => ent.id), onAttach, onHide , addText = "Add",
emptyState = 'No matches', modalTitle = 'Add', headers = ['Select', 'ID'],
filterPlaceholder = 'Filter...'}) => {
const search = useRef(null);
Expand Down Expand Up @@ -49,7 +42,7 @@ export const AttachModal = ({ show, searchFn, onAttach, onHide, addText = "Add",
onAdd={() => setSelected([...selected, ent])}
onRemove={() => setSelected(selected.filter(selectedEnt => selectedEnt.id !== ent.id))}
name={'selected'}/>,
<strong>{resolveEntityDisplayName(ent)}</strong>
<strong>{resolveEntityFn(ent)}</strong>
]}/>

<div className="mt-3">
Expand All @@ -58,7 +51,7 @@ export const AttachModal = ({ show, searchFn, onAttach, onHide, addText = "Add",
<strong>Selected: </strong>
{(selected.map(item => (
<Badge key={item.id} pill variant="primary" className="me-1">
{resolveEntityDisplayName(item)}
{resolveEntityFn(item)}
</Badge>
)))}
</p>
Expand Down
20 changes: 20 additions & 0 deletions webui/src/lib/components/auth/users.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import {auth, MAX_LISTING_AMOUNT} from "../../api";

export const allUsersFromLakeFS = async (resolveUserDisplayNameFN = (user => user.id)) => {
let after = ""
let hasMore = true
let usersList = []
try {
do {
const results = await auth.listUsers("", after, MAX_LISTING_AMOUNT);
usersList = usersList.concat(results.results);
after = results.pagination.next_offset;
hasMore = results.pagination.has_more;
} while (hasMore);
usersList.sort((a, b) => resolveUserDisplayNameFN(a).localeCompare(resolveUserDisplayNameFN(b)));
return usersList;
} catch (error) {
console.error("Error fetching users:", error);
return [];
}
}
2 changes: 1 addition & 1 deletion webui/src/lib/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ interface User {
friendly_name: string;
}

export const resolveDisplayName = (user: User): string => {
export const resolveUserDisplayName = (user: User): string => {
if (!user) return "";
if (user?.email?.length) return user.email;
if (user?.friendly_name?.length) return user.friendly_name;
Expand Down
4 changes: 2 additions & 2 deletions webui/src/pages/auth/credentials.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import {auth} from "../../lib/api";
import {useState} from "react";
import {CredentialsShowModal, CredentialsTable} from "../../lib/components/auth/credentials";
import {useRouter} from "../../lib/hooks/router";
import {resolveDisplayName} from "../../lib/utils";
import {resolveUserDisplayName} from "../../lib/utils";

const CredentialsContainer = () => {
const router = useRouter();
Expand Down Expand Up @@ -40,7 +40,7 @@ const CredentialsContainer = () => {
<ConfirmationButton
variant="success"
modalVariant="success"
msg={<span>Create a new Access Key for user <strong>{resolveDisplayName(user)}</strong>?</span>}
msg={<span>Create a new Access Key for user <strong>{resolveUserDisplayName(user)}</strong>?</span>}
onConfirm={hide => {
createKey()
.then(key => { setCreatedKey(key) })
Expand Down
23 changes: 17 additions & 6 deletions webui/src/pages/auth/groups/group/members.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,22 +19,32 @@ import {
} from "../../../../lib/components/controls";
import {useRouter} from "../../../../lib/hooks/router";
import {Link} from "../../../../lib/components/nav";
import {resolveDisplayName} from "../../../../lib/utils";
import {resolveUserDisplayName} from "../../../../lib/utils";
import {allUsersFromLakeFS} from "../../../../lib/components/auth/users";


const GroupMemberList = ({ groupId, after, onPaginate }) => {
const [refresh, setRefresh] = useState(false);
const [showAddModal, setShowAddModal] = useState(false);
const [attachError, setAttachError] = useState(null);

const [allUsers, setAllUsers] = useState([]);
const {results, loading, error, nextPage} = useAPIWithPagination(() => {
return auth.listGroupMembers(groupId, after);
}, [groupId, after, refresh]);

useEffect(() => {
setAttachError(null);
}, [refresh]);


const searchUsers = async (prefix, maxResults, resolveUserDisplayNameFN = (user => user.id)) => {
let allUsersList = allUsers;
if (allUsersList.length == 0) {

Check warning on line 41 in webui/src/pages/auth/groups/group/members.jsx

View workflow job for this annotation

GitHub Actions / Run Linters and Checkers

Expected '===' and instead saw '=='

Check warning on line 41 in webui/src/pages/auth/groups/group/members.jsx

View workflow job for this annotation

GitHub Actions / Run Linters and Checkers

Expected '===' and instead saw '=='

Check warning on line 41 in webui/src/pages/auth/groups/group/members.jsx

View workflow job for this annotation

GitHub Actions / Analyze

Expected '===' and instead saw '=='

Check warning on line 41 in webui/src/pages/auth/groups/group/members.jsx

View workflow job for this annotation

GitHub Actions / Test React App

Expected '===' and instead saw '=='

Check warning on line 41 in webui/src/pages/auth/groups/group/members.jsx

View workflow job for this annotation

GitHub Actions / Generate code from latest lakeFS app

Expected '===' and instead saw '=='

Check warning on line 41 in webui/src/pages/auth/groups/group/members.jsx

View workflow job for this annotation

GitHub Actions / Build and push Docker image

Expected '===' and instead saw '=='

Check warning on line 41 in webui/src/pages/auth/groups/group/members.jsx

View workflow job for this annotation

GitHub Actions / Build and push Docker image

Expected '===' and instead saw '=='
allUsersList = await allUsersFromLakeFS(resolveUserDisplayNameFN)
setAllUsers(allUsersList)
}
let filteredUsers = allUsersList.filter(user => resolveUserDisplayNameFN(user).startsWith(prefix));
return filteredUsers.slice(0, maxResults);
};
let content;
if (loading) content = <Loading/>;
else if (error) content= <AlertError error={error}/>;
Expand All @@ -45,7 +55,7 @@ const GroupMemberList = ({ groupId, after, onPaginate }) => {
<DataTable
keyFn={user => user.id}
rowFn={user => [
<Link href={{pathname: '/auth/users/:userId', params: {userId: user.id}}}>{resolveDisplayName(user)}</Link>,
<Link href={{pathname: '/auth/users/:userId', params: {userId: user.id}}}>{resolveUserDisplayName(user)}</Link>,
<FormattedDate dateValue={user.creation_date}/>
]}
headers={['User ID', 'Created At']}
Expand All @@ -54,7 +64,7 @@ const GroupMemberList = ({ groupId, after, onPaginate }) => {
buttonFn: user => <ConfirmationButton
size="sm"
variant="outline-danger"
msg={<span>Are you sure you{'\''}d like to remove user <strong>{resolveDisplayName(user)}</strong> from group <strong>{groupId}</strong>?</span>}
msg={<span>Are you sure you{'\''}d like to remove user <strong>{resolveUserDisplayName(user)}</strong> from group <strong>{groupId}</strong>?</span>}
onConfirm={() => {
auth.removeUserFromGroup(user.id, groupId)
.catch(error => alert(error))
Expand All @@ -75,7 +85,8 @@ const GroupMemberList = ({ groupId, after, onPaginate }) => {
filterPlaceholder={'Find User...'}
modalTitle={'Add to Group'}
addText={'Add to Group'}
searchFn={prefix => auth.listUsers(prefix, "", 5).then(res => res.results)}
resolveEntityFn={resolveUserDisplayName}
searchFn={prefix => searchUsers(prefix, 5, resolveUserDisplayName).then(res => res)}
onHide={() => setShowAddModal(false)}
onAttach={(selected) => {
Promise.all(selected.map(user => auth.addUserToGroup(user.id, groupId)))
Expand Down
4 changes: 2 additions & 2 deletions webui/src/pages/auth/users/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import {
} from "../../../lib/components/controls";
import validator from "validator/es";
import { disallowPercentSign, INVALID_USER_NAME_ERROR_MESSAGE } from "../validation";
import { resolveDisplayName } from "../../../lib/utils";
import { resolveUserDisplayName } from "../../../lib/utils";

const USER_NOT_FOUND = "unknown";
export const GetUserEmailByIdContext = createContext();
Expand Down Expand Up @@ -119,7 +119,7 @@ const UsersContainer = ({nextPage, refresh, setRefresh, error, loading, userList
onRemove={() => setSelected(selected.filter(u => u !== user))}
/>,
<Link href={{pathname: '/auth/users/:userId', params: {userId: user.id}}}>
{ resolveDisplayName(user) }
{ resolveUserDisplayName(user) }
</Link>,
<FormattedDate dateValue={user.creation_date}/>
]}/>
Expand Down
10 changes: 9 additions & 1 deletion webui/src/pages/auth/users/user/groups.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,12 @@ import { ConfirmationButton } from "../../../../lib/components/modals";
import { useRouter } from "../../../../lib/hooks/router";
import { Link } from "../../../../lib/components/nav";

const resolveGroupDisplayName = (group) => {
if(!group) return "";
if (group?.name?.length) return group.name;
return group.id;
}

const UserGroupsList = ({ userId, after, onPaginate }) => {
const [refresh, setRefresh] = useState(false);
const [showAddModal, setShowAddModal] = useState(false);
Expand Down Expand Up @@ -97,6 +103,7 @@ const UserGroupsList = ({ userId, after, onPaginate }) => {
searchFn={(prefix) =>
auth.listGroups(prefix, "", 5).then((res) => res.results)
}
resolveEntityFn={resolveGroupDisplayName}
onHide={() => setShowAddModal(false)}
onAttach={(selected) => {
Promise.all(
Expand All @@ -112,7 +119,8 @@ const UserGroupsList = ({ userId, after, onPaginate }) => {
.finally(() => {
setShowAddModal(false);
});
}}
}
}
/>
)}
</>
Expand Down

0 comments on commit e74938c

Please sign in to comment.