Skip to content

Commit

Permalink
Support Group Description in the WebUI
Browse files Browse the repository at this point in the history
  • Loading branch information
itaigilo committed Dec 27, 2024
1 parent b34740e commit a8a8fb0
Show file tree
Hide file tree
Showing 5 changed files with 85 additions and 19 deletions.
15 changes: 13 additions & 2 deletions webui/src/lib/api/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -300,14 +300,25 @@ class Auth {
}
}

async createGroup(groupName) {
const response = await apiRequest(`/auth/groups`, {method: 'POST', body: JSON.stringify({id: groupName})});
async createGroup(groupName, groupDescription) {
const response = await apiRequest(`/auth/groups`, {method: 'POST', body: JSON.stringify({
id: groupName,
description: groupDescription
})});
if (response.status !== 201) {
throw new Error(await extractError(response));
}
return response.json();
}

async getGroup(groupId) {
const response = await apiRequest(`/auth/groups/${encodeURIComponent(groupId)}`);
if (response.status !== 200) {
throw new Error(`could not get groups: ${await extractError(response)}`);
}
return response.json();
}

async listPolicies(prefix = "", after = "", amount = DEFAULT_LISTING_AMOUNT) {
const query = qs({prefix, after, amount});
const response = await apiRequest(`/auth/policies?${query}`);
Expand Down
29 changes: 26 additions & 3 deletions webui/src/lib/components/auth/forms.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -91,13 +91,26 @@ export const AttachModal = ({ show, searchFn, resolveEntityFn = (ent => ent.id),
);
};

export const EntityActionModal = ({ show, onHide, onAction, title, placeholder, actionName, validationFunction = null }) => {
export const EntityActionModal = ({
show,
onHide,
onAction,
title,
placeholder,
actionName,
validationFunction = null,
showExtraField = false,
extraPlaceholder = "",
extraValidationFunction = null
}) => {
const [error, setError] = useState(null);
const idField = useRef(null);
const extraField = useRef(null);

useEffect(() => {
if (!!idField.current && idField.current.value === "")
if (!!idField.current && idField.current.value === "") {
idField.current.focus();
}
});

const onSubmit = () => {
Expand All @@ -108,7 +121,14 @@ export const EntityActionModal = ({ show, onHide, onAction, title, placeholder,
return;
}
}
onAction(idField.current.value).catch(err => setError(err));
if (showExtraField && extraValidationFunction) {
const validationResult = extraValidationFunction(extraField.current.value);
if (!validationResult.isValid) {
setError(validationResult.errorMessage);
return;
}
}
onAction(idField.current.value, extraField.current.value).catch(err => setError(err));
};

return (
Expand All @@ -123,6 +143,9 @@ export const EntityActionModal = ({ show, onHide, onAction, title, placeholder,
onSubmit()
}}>
<FormControl ref={idField} autoFocus placeholder={placeholder} type="text"/>
{showExtraField &&
<FormControl ref={extraField} placeholder={extraPlaceholder} type="text" className="mt-3"/>
}
</Form>

{(!!error) && <AlertError className="mt-3" error={error}/>}
Expand Down
45 changes: 34 additions & 11 deletions webui/src/lib/components/auth/nav.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import {BreadcrumbItem} from "react-bootstrap";
import {useLoginConfigContext} from "../../hooks/conf";

import {Link, NavItem} from "../nav";
import {useAPI} from "../../hooks/api";
import {auth} from "../../api";


export const UserNav = ({ userId, page = 'groups' }) => {
Expand Down Expand Up @@ -39,20 +41,41 @@ export const UserNav = ({ userId, page = 'groups' }) => {

export const GroupNav = ({ groupId, page = 'groups' }) => {
const {RBAC: rbac} = useLoginConfigContext();

const {response, loading, error} = useAPI(() => {
return auth.getGroup(groupId);
}, [groupId]);

const group = response;

function getDescription() {
if (loading) return <span>...</span>;
if (error) return <span className="text-danger">{error.message}</span>;
return group && group.description;
}

return (
<>
{rbac === 'simplified' ?
<Link component={NavItem} active={page === 'members'} href={{pathname: '/auth/groups/:groupId/members', params: {groupId}}}>
Group Memberships
</Link> :
<Nav justify variant="tabs">
<Link component={NavItem} active={page === 'members'} href={{pathname: '/auth/groups/:groupId/members', params: {groupId}}}>
Group Memberships
</Link>
<Link component={NavItem} active={page === 'policies'} href={{pathname: '/auth/groups/:groupId/policies', params: {groupId}}}>
Attached Policies
</Link>
</Nav>}
<Link component={NavItem} active={page === 'members'}
href={{pathname: '/auth/groups/:groupId/members', params: {groupId}}}>
Group Memberships
</Link>
:
<div>
<h6 className="mb-4">Group description: {getDescription()}</h6>
<Nav justify variant="tabs">
<Link component={NavItem} active={page === 'members'}
href={{pathname: '/auth/groups/:groupId/members', params: {groupId}}}>
Group Memberships
</Link>
<Link component={NavItem} active={page === 'policies'}
href={{pathname: '/auth/groups/:groupId/policies', params: {groupId}}}>
Attached Policies
</Link>
</Nav>
</div>
}
</>
);
};
Expand Down
13 changes: 10 additions & 3 deletions webui/src/pages/auth/groups/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,11 @@ import {
import {useRouter} from "../../../lib/hooks/router";
import {Link} from "../../../lib/components/nav";
import {EntityActionModal} from "../../../lib/components/auth/forms";
import { disallowPercentSign, INVALID_GROUP_NAME_ERROR_MESSAGE } from "../validation";
import {
disallowPercentSign,
INVALID_GROUP_NAME_ERROR_MESSAGE,
INVALID_GROUP_DESCRIPTION_ERROR_MESSAGE
} from "../validation";
import {useLoginConfigContext} from "../../../lib/hooks/conf";
import {useAuthOutletContext} from "../../../lib/components/auth/layout";

Expand Down Expand Up @@ -160,8 +164,8 @@ const GroupsContainer = () => {
<EntityActionModal
show={showCreate}
onHide={() => setShowCreate(false)}
onAction={groupName => {
return auth.createGroup(groupName).then(() => {
onAction={(groupName, groupDesc) => {
return auth.createGroup(groupName, groupDesc).then(() => {
setSelected([]);
setShowCreate(false);
setRefresh(!refresh);
Expand All @@ -171,6 +175,9 @@ const GroupsContainer = () => {
placeholder="Group Name (e.g. 'DataTeam')"
actionName={"Create"}
validationFunction={disallowPercentSign(INVALID_GROUP_NAME_ERROR_MESSAGE)}
showExtraField={true}
extraPlaceholder="Group Description (optional)"
extraValidationFunction={disallowPercentSign(INVALID_GROUP_DESCRIPTION_ERROR_MESSAGE)}
/>

<DataTable
Expand Down
2 changes: 2 additions & 0 deletions webui/src/pages/auth/validation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ export const INVALID_USER_NAME_ERROR_MESSAGE: ValidationError =
"User name cannot include the % sign";
export const INVALID_GROUP_NAME_ERROR_MESSAGE: ValidationError =
"Group name cannot include the % sign";
export const INVALID_GROUP_DESCRIPTION_ERROR_MESSAGE: ValidationError =
"Group description cannot include the % sign";
export const INVALID_POLICY_ID_ERROR_MESSAGE: ValidationError =
"Policy ID cannot include the % sign";

Expand Down

0 comments on commit a8a8fb0

Please sign in to comment.