Skip to content

Commit

Permalink
ISPN-14697 Role detail
Browse files Browse the repository at this point in the history
  • Loading branch information
karesti committed Oct 26, 2023
1 parent e4e0b1a commit 48ed6f0
Show file tree
Hide file tree
Showing 18 changed files with 661 additions and 83 deletions.
35 changes: 16 additions & 19 deletions src/app/AccessManagement/CreateRole.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,27 +26,24 @@ import { useTranslation } from 'react-i18next';
import formUtils, { IField } from '@services/formUtils';
import { AddCircleOIcon, ExclamationCircleIcon, TimesIcon } from '@patternfly/react-icons';
import { useCreateRole, useFetchAvailableRoles } from '@app/services/rolesHook';
import { PERMISSIONS_MAP } from '@services/infinispanRefData';

const CreateRole = (props: { isModalOpen: boolean; submitModal: () => void; closeModal: () => void }) => {
const { t } = useTranslation();
const { roles } = useFetchAvailableRoles();
const brandname = t('brandname.brandname');
const initialSelectOptions: SelectOptionProps[] = [
{ value: 'ALL', children: 'ALL', description: t('access-management.roles.permission-all') },
{ value: 'ADMIN', children: 'ADMIN', description: t('access-management.roles.permission-admin') },
{ value: 'ALL_READ', children: 'ALL_READ', description: t('access-management.roles.permission-all-read') },
{ value: 'READ', children: 'READ', description: t('access-management.roles.permission-read') },
{ value: 'BULK_READ', children: 'BULK_READ', description: t('access-management.roles.permission-bulk-read') },
{ value: 'ALL_WRITE', children: 'ALL_WRITE', description: t('access-management.roles.permission-all-write') },
{ value: 'WRITE', children: 'WRITE', description: t('access-management.roles.permission-write') },
{ value: 'BULK_WRITE', children: 'BULK_WRITE', description: t('access-management.roles.permission-bulk-write') },
{ value: 'MONITOR', children: 'MONITOR', description: t('access-management.roles.permission-monitor') },
{ value: 'CREATE', children: 'CREATE', description: t('access-management.roles.permission-create') },
{ value: 'EXEC', children: 'EXEC', description: t('access-management.roles.permission-exec') },
{ value: 'LISTEN', children: 'LISTEN', description: t('access-management.roles.permission-listen') },
{ value: 'LIFECYCLE', children: 'LIFECYCLE', description: t('access-management.roles.permission-lifecycle') },
{ value: 'NONE', children: 'NONE', description: t('access-management.roles.permission-none') }
];
const initPermissions = () => {
let array: SelectOptionProps[] = [];
PERMISSIONS_MAP.forEach((value, key, map) => {
array.push({
value: key,
children: key,
description: value
})
})
return array;
};
const initialSelectOptions: SelectOptionProps[] = initPermissions();

const roleNameInitialState: IField = {
value: '',
isValid: false,
Expand Down Expand Up @@ -247,7 +244,7 @@ const CreateRole = (props: { isModalOpen: boolean; submitModal: () => void; clos
{t('access-management.roles.modal-save-action')}
</Button>,
<Button key={'Cancel'} aria-label={'Cancel'} variant={ButtonVariant.link} onClick={onCloseModal}>
{t('access-management.roles.modal-cancel-button')}
{t('common.actions.cancel')}
</Button>
]}
>
Expand Down Expand Up @@ -322,7 +319,7 @@ const CreateRole = (props: { isModalOpen: boolean; submitModal: () => void; clos
{...option}
hasCheckbox
isSelected={selectedPermissions.includes(option.value)}
description={option.description}
description={t(option.description as string)}
ref={null}
/>
))}
Expand Down
95 changes: 95 additions & 0 deletions src/app/AccessManagement/RoleDetail.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
import React, { useEffect, useState } from 'react';
import {
Card,
CardBody,
Nav,
NavItem,
NavList,
PageSection,
PageSectionVariants,
Text,
TextContent,
TextVariants
} from '@patternfly/react-core';
import { useTranslation } from 'react-i18next';
import { DataContainerBreadcrumb } from '@app/Common/DataContainerBreadcrumb';
import { global_spacer_md, global_spacer_sm } from '@patternfly/react-tokens';
import { RoleGeneral } from '@app/AccessManagement/RoleDetailContent/RoleGeneral';
import { RolePermissions } from '@app/AccessManagement/RoleDetailContent/RolePermissions';

const RoleDetail = (props) => {
const roleName = decodeURIComponent(props.computedMatch.params.roleName);
const { t } = useTranslation();
const brandname = t('brandname.brandname');
const [activeTabKey, setActiveTabKey] = useState('0');
const [showGeneralDescription, setShowGeneralDescription] = useState(true);
const [showPermissions, setShowPermissions] = useState(false);
const [showCaches, setShowCaches] = useState(false);

useEffect(() => {
setShowGeneralDescription(activeTabKey === '0');
setShowPermissions(activeTabKey === '1');
setShowCaches(activeTabKey === '2');
}, [activeTabKey]);

interface AccessTab {
key: string;
name: string;
}

const handleTabClick = (event, nav) => {
setActiveTabKey(nav.itemId);
};

const tabs: AccessTab[] = [
{ name: t('access-management.role.tab-general'), key: '0' },
{ name: t('access-management.role.tab-permissions'), key: '1' },
// { name: t('access-management.role.tab-caches'), key: '2' }
];

const buildTabs = () => {
return (
<Nav data-cy="navigationTabs" onSelect={handleTabClick} variant={'tertiary'}>
<NavList>
{tabs.map((tab) => (
<NavItem
aria-label={'nav-item-' + tab.name}
key={'nav-item-' + tab.key}
itemId={tab.key}
isActive={activeTabKey === tab.key}
>
{tab.name}
</NavItem>
))}
</NavList>
</Nav>
);
};

const buildSelectedContent = (
<Card>
<CardBody>
{showGeneralDescription && <RoleGeneral name={roleName}/>}
{showPermissions && <RolePermissions name={roleName}/>}
{/*{showCaches && <RoleCaches />}*/}
</CardBody>
</Card>
);

return (
<>
<PageSection variant={PageSectionVariants.light} style={{ paddingBottom: 0 }}>
<DataContainerBreadcrumb parentPage={'/access-management'}
label={'access-management.title'}
currentPage={t('access-management.role.breadcrumb', { roleName: roleName })} />
<TextContent style={{ marginTop: global_spacer_md.value, marginBottom: global_spacer_sm.value }}>
<Text component={TextVariants.h1}>{roleName}</Text>
</TextContent>
{buildTabs()}
</PageSection>
<PageSection variant={PageSectionVariants.default}>{buildSelectedContent}</PageSection>
</>
);
};

export { RoleDetail };
12 changes: 12 additions & 0 deletions src/app/AccessManagement/RoleDetailContent/RoleCaches.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { useTranslation } from 'react-i18next';

const RoleCaches = () => {
const { t } = useTranslation();
const brandname = t('brandname.brandname');

return (
"Caches"
)
};

export { RoleCaches };
174 changes: 174 additions & 0 deletions src/app/AccessManagement/RoleDetailContent/RoleGeneral.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
import { useTranslation } from 'react-i18next';
import { useDescribeRole } from '@app/services/rolesHook';
import {
ActionGroup,
Alert,
Button,
ButtonVariant,
EmptyState,
EmptyStateActions,
EmptyStateBody,
EmptyStateFooter,
EmptyStateHeader,
EmptyStateIcon,
EmptyStateVariant,
Form,
FormGroup,
FormHelperText,
HelperText,
HelperTextItem,
Spinner,
TextInput
} from '@patternfly/react-core';
import * as React from 'react';
import { useEffect, useState } from 'react';
import { ExclamationCircleIcon } from '@patternfly/react-icons';
import { global_danger_color_200 } from '@patternfly/react-tokens';
import { Link } from 'react-router-dom';
import formUtils, { IField } from '@services/formUtils';

const RoleGeneral= (props: { name: string }) => {
const roleNameInitialState: IField = {
value: '',
isValid: false,
validated: 'default'
};

const roleDescriptionInitialState: IField = {
value: '',
isValid: false,
validated: 'default'
};

const { t } = useTranslation();
const {role, loading, error, setLoading} = useDescribeRole(props.name);
const brandname = t('brandname.brandname');
const [roleName, setRoleName] = useState<IField>(roleNameInitialState);
const [roleDescription, setRoleDescription] = useState<IField>(roleDescriptionInitialState);
const [isImplicit, setIsImplicit] = useState<boolean>(false);

useEffect(() => {
if (role) {
setRoleName({
...roleName,
value: role.name
});
setRoleDescription({
...roleDescription,
value: role.description
})
setIsImplicit(role.implicit);
}
}, [role]);

const buildDetailContent = () => {
if (loading && !role) {
return (
<Spinner size='xl' />
);
}

if (error !== '') {
return (
<EmptyState variant={EmptyStateVariant.sm}>
<EmptyStateHeader
titleText={t('access-management.role.error', {roleName: props.name})}
icon={<EmptyStateIcon icon={ExclamationCircleIcon} color={global_danger_color_200.value} />}
headingLevel="h2"
/>
<EmptyStateBody>{error}</EmptyStateBody>
<EmptyStateFooter>
<EmptyStateActions>
<Link
to={{
pathname: '/access-management',
search: location.search
}}
>
<Button variant={ButtonVariant.secondary}>{t('common.actions.back')}</Button>
</Link>
</EmptyStateActions>
</EmptyStateFooter>
</EmptyState>
)
}

const displayImplicitRoleMessage = () => {
return role?.implicit && (
<Alert
isInline
isPlain
variant={'warning'}
title={t('access-management.role.implicit-warning')}
/>
);
}
return (
<Form isHorizontal isWidthLimited
onSubmit={(e) => {
e.preventDefault();
}}
>
{displayImplicitRoleMessage()}
<FormGroup isRequired isInline disabled={role?.implicit} label={t('access-management.roles.modal-role-name')}>
<TextInput
isDisabled={role?.implicit}
validated={roleName.validated}
value={roleName.value}
type="text"
onChange={(_event, value) =>
formUtils.validateRequiredField(value, t('access-management.roles.modal-role-name'), setRoleName)
}
aria-label="role-name-input"
/>
{roleName.validated === 'error' && (
<FormHelperText>
<HelperText>
<HelperTextItem variant={'error'} icon={<ExclamationCircleIcon />}>
{roleName.invalidText}
</HelperTextItem>
</HelperText>
</FormHelperText>
)}
</FormGroup>
<FormGroup isInline disabled={role?.implicit} label={t('access-management.roles.modal-role-description')}>
<TextInput
isDisabled={role?.implicit}
validated={roleDescription.validated}
value={roleDescription.value}
type="text"
onChange={(_event, value) =>
formUtils.validateRequiredField(
value,
t('access-management.roles.modal-role-description'),
setRoleDescription
)
}
aria-label="role-description-input"
/>
{roleDescription.validated === 'error' && (
<FormHelperText>
<HelperText>
<HelperTextItem variant={'error'} icon={<ExclamationCircleIcon />}>
{roleDescription.invalidText}
</HelperTextItem>
</HelperText>
</FormHelperText>
)}
</FormGroup>
<ActionGroup>
<Button isDisabled={role?.implicit} key={'Save'} aria-label={'Save'} variant={ButtonVariant.primary}>
{t('common.actions.save')}
</Button>
<Button isDisabled={role?.implicit} key={'Cancel'} aria-label={'Cancel'} variant={ButtonVariant.link} onClick={(e) => setLoading(true)}>
{t('common.actions.cancel')}
</Button>
</ActionGroup>
</Form>
)
}

return buildDetailContent();
};

export { RoleGeneral };
Loading

0 comments on commit 48ed6f0

Please sign in to comment.