From e91d3ab02512f7e195616b36af4a863c782d043b Mon Sep 17 00:00:00 2001 From: lgalis Date: Mon, 26 Aug 2024 14:07:16 -0400 Subject: [PATCH] Update empty pages and add permission checks for the create button Add rbac checks for the Event stream actions and the edit page --- .../hooks/useMapContentTypeToDisplayName.tsx | 1 + .../eda/event-streams/EventStreamForm.tsx | 52 ++++++++++++++----- .../EventStreamPage/EventStreamPage.tsx | 22 +++++++- .../EventStreamPage/EventStreamUserAccess.tsx | 2 +- frontend/eda/event-streams/EventStreams.tsx | 27 ++++++++-- .../hooks/useEventStreamsActions.tsx | 12 ++++- 6 files changed, 95 insertions(+), 21 deletions(-) diff --git a/frontend/common/access/hooks/useMapContentTypeToDisplayName.tsx b/frontend/common/access/hooks/useMapContentTypeToDisplayName.tsx index b93ba34bd2..1b4bdb2089 100644 --- a/frontend/common/access/hooks/useMapContentTypeToDisplayName.tsx +++ b/frontend/common/access/hooks/useMapContentTypeToDisplayName.tsx @@ -22,6 +22,7 @@ export function useMapContentTypeToDisplayName() { decisionenvironment: options?.isTitleCase ? t('Decision Environment') : t('decision environment'), + eventstream: options?.isTitleCase ? t('Event Stream') : t('event stream'), auditrule: options?.isTitleCase ? t('Rule Audit') : t('rule audit'), team: options?.isTitleCase ? t('Team') : t('team'), organization: options?.isTitleCase ? t('Organization') : t('organization'), diff --git a/frontend/eda/event-streams/EventStreamForm.tsx b/frontend/eda/event-streams/EventStreamForm.tsx index 0e1deb2280..0f2db8b47b 100644 --- a/frontend/eda/event-streams/EventStreamForm.tsx +++ b/frontend/eda/event-streams/EventStreamForm.tsx @@ -27,6 +27,10 @@ import { useFormContext, useWatch } from 'react-hook-form'; import { EdaCredentialType } from '../interfaces/EdaCredentialType'; import { useEffect } from 'react'; import { PageFormHidden } from '../../../framework/PageForm/Utils/PageFormHidden'; +import { useOptions } from '../../common/crud/useOptions'; +import { ActionsResponse, OptionsResponse } from '../interfaces/OptionsResponse'; +import { Alert } from '@patternfly/react-core'; +import { EventStreamDetails } from './EventStreamPage/EventStreamDetails'; // eslint-disable-next-line react/prop-types function EventStreamInputs() { @@ -211,6 +215,8 @@ export function EditEventStream() { const navigate = useNavigate(); const params = useParams<{ id?: string }>(); const id = Number(params.id); + const { data } = useOptions>(edaAPI`/event-streams/`); + const canEditEventStream = Boolean(data && data.actions && data.actions['PATCH']); const { data: eventStream } = useGet(edaAPI`/event-streams/${id.toString()}/`); const { cache } = useSWRConfig(); @@ -245,19 +251,39 @@ export function EditEventStream() { { label: `${t('Edit')} ${eventStream?.name || t('event stream')}` }, ]} /> - - - + {!canEditEventStream ? ( + <> + + + + ) : ( + + + + )} ); } diff --git a/frontend/eda/event-streams/EventStreamPage/EventStreamPage.tsx b/frontend/eda/event-streams/EventStreamPage/EventStreamPage.tsx index bd3e4ab9f4..8c975aa30a 100644 --- a/frontend/eda/event-streams/EventStreamPage/EventStreamPage.tsx +++ b/frontend/eda/event-streams/EventStreamPage/EventStreamPage.tsx @@ -22,11 +22,15 @@ import { EdaEventStream } from '../../interfaces/EdaEventStream'; import { EdaRoute } from '../../main/EdaRoutes'; import { useDeleteEventStreams } from '../hooks/useDeleteEventStreams'; import { usePatchRequest } from '../../../common/crud/usePatchRequest'; +import { useOptions } from '../../../common/crud/useOptions'; +import { ActionsResponse, OptionsResponse } from '../../interfaces/OptionsResponse'; export function EventStreamPage() { const { t } = useTranslation(); const params = useParams<{ id: string }>(); const pageNavigate = usePageNavigate(); + const { data } = useOptions>(edaAPI`/event-streams/`); + const canEditEventStream = Boolean(data && data.actions && data.actions['PATCH']); const { data: eventStream } = useGet(edaAPI`/event-streams/${params.id ?? ''}/`); const patchRequest = usePatchRequest(); const alertToaster = usePageAlertToaster(); @@ -71,6 +75,10 @@ export function EventStreamPage() { icon: PencilAltIcon, isPinned: true, label: t('Edit event stream'), + isDisabled: () => + canEditEventStream + ? '' + : t(`The event stream cannot be edited due to insufficient permission`), onClick: (eventStream: EdaEventStream) => pageNavigate(EdaRoute.EditEventStream, { params: { id: eventStream.id } }), }, @@ -79,6 +87,10 @@ export function EventStreamPage() { selection: PageActionSelection.Single, icon: TaskIcon, label: t('Switch to test mode'), + isDisabled: () => + canEditEventStream + ? '' + : t(`The event stream cannot be updated due to insufficient permission`), isHidden: (eventStream: EdaEventStream) => !!eventStream?.test_mode, onClick: (eventStream: EdaEventStream) => toggleEventStreamMode(true, eventStream), }, @@ -87,6 +99,10 @@ export function EventStreamPage() { selection: PageActionSelection.Single, icon: DatabaseIcon, label: t('Switch to production mode'), + isDisabled: () => + canEditEventStream + ? '' + : t(`The event stream cannot be updated due to insufficient permission`), isHidden: (eventStream: EdaEventStream) => !eventStream?.test_mode, onClick: (eventStream: EdaEventStream) => toggleEventStreamMode(false, eventStream), }, @@ -98,11 +114,15 @@ export function EventStreamPage() { selection: PageActionSelection.Single, icon: TrashIcon, label: t('Delete event stream'), + isDisabled: () => + canEditEventStream + ? '' + : t(`The event stream cannot be deleted due to insufficient permission`), onClick: (eventStream: EdaEventStream) => deleteEventStreams([eventStream]), isDanger: true, }, ], - [deleteEventStreams, pageNavigate, t, toggleEventStreamMode] + [canEditEventStream, deleteEventStreams, pageNavigate, t, toggleEventStreamMode] ); const getPageUrl = useGetPageUrl(); diff --git a/frontend/eda/event-streams/EventStreamPage/EventStreamUserAccess.tsx b/frontend/eda/event-streams/EventStreamPage/EventStreamUserAccess.tsx index 85ffc5422d..a6aefb0cf2 100644 --- a/frontend/eda/event-streams/EventStreamPage/EventStreamUserAccess.tsx +++ b/frontend/eda/event-streams/EventStreamPage/EventStreamUserAccess.tsx @@ -8,7 +8,7 @@ export function EventStreamUserAccess() { ); diff --git a/frontend/eda/event-streams/EventStreams.tsx b/frontend/eda/event-streams/EventStreams.tsx index a3c544235e..06003592ef 100644 --- a/frontend/eda/event-streams/EventStreams.tsx +++ b/frontend/eda/event-streams/EventStreams.tsx @@ -8,7 +8,9 @@ import { useEventStreamActions } from './hooks/useEventStreamActions'; import { useEventStreamColumns } from './hooks/useEventStreamColumns'; import { useEventStreamFilters } from './hooks/useEventStreamFilters'; import { useEventStreamsActions } from './hooks/useEventStreamsActions'; -import { PlusCircleIcon } from '@patternfly/react-icons'; +import { CubesIcon, PlusCircleIcon } from '@patternfly/react-icons'; +import { useOptions } from '../../common/crud/useOptions'; +import { ActionsResponse, OptionsResponse } from '../interfaces/OptionsResponse'; export function EventStreams() { const { t } = useTranslation(); @@ -21,6 +23,8 @@ export function EventStreams() { tableColumns, }); const toolbarActions = useEventStreamsActions(view); + const { data } = useOptions>(edaAPI`/event-streams/`); + const canCreateEventStream = Boolean(data && data.actions && data.actions['POST']); const rowActions = useEventStreamActions(view); return ( @@ -38,11 +42,24 @@ export function EventStreams() { toolbarFilters={toolbarFilters} rowActions={rowActions} errorStateTitle={t('Error loading event streams')} - emptyStateTitle={t('There are currently no event streams created for your organization.')} - emptyStateDescription={t('Please create an event stream by using the button below.')} + emptyStateTitle={ + canCreateEventStream + ? t('There are currently no event streams created for your organization.') + : t('You do not have permission to create an event stream.') + } + emptyStateDescription={ + canCreateEventStream + ? t('Please create an event stream by using the button below.') + : t( + 'Please contact your organization administrator if there is an issue with your access.' + ) + } + emptyStateIcon={canCreateEventStream ? undefined : CubesIcon} emptyStateButtonIcon={} - emptyStateButtonText={t('Create event stream')} - emptyStateButtonClick={() => pageNavigate(EdaRoute.CreateEventStream)} + emptyStateButtonText={canCreateEventStream ? t('Create event stream') : undefined} + emptyStateButtonClick={ + canCreateEventStream ? () => pageNavigate(EdaRoute.CreateEventStream) : undefined + } {...view} defaultSubtitle={t('Event stream')} /> diff --git a/frontend/eda/event-streams/hooks/useEventStreamsActions.tsx b/frontend/eda/event-streams/hooks/useEventStreamsActions.tsx index 74b696ee25..0cefed6d6c 100644 --- a/frontend/eda/event-streams/hooks/useEventStreamsActions.tsx +++ b/frontend/eda/event-streams/hooks/useEventStreamsActions.tsx @@ -12,11 +12,16 @@ import { IEdaView } from '../../common/useEventDrivenView'; import { EdaEventStream } from '../../interfaces/EdaEventStream'; import { EdaRoute } from '../../main/EdaRoutes'; import { useDeleteEventStreams } from './useDeleteEventStreams'; +import { useOptions } from '../../../common/crud/useOptions'; +import { ActionsResponse, OptionsResponse } from '../../interfaces/OptionsResponse'; +import { edaAPI } from '../../common/eda-utils'; export function useEventStreamsActions(view: IEdaView) { const { t } = useTranslation(); const pageNavigate = usePageNavigate(); const deleteEventStreams = useDeleteEventStreams(view.unselectItemsAndRefresh); + const { data } = useOptions>(edaAPI`/event-streams/`); + const canCreateEventStream = Boolean(data && data.actions && data.actions['POST']); return useMemo[]>( () => [ { @@ -26,6 +31,11 @@ export function useEventStreamsActions(view: IEdaView) { isPinned: true, icon: PlusCircleIcon, label: t('Create event stream'), + isDisabled: canCreateEventStream + ? undefined + : t( + 'You do not have permission to create a project. Please contact your organization administrator if there is an issue with your access.' + ), onClick: () => pageNavigate(EdaRoute.CreateEventStream), }, { @@ -37,6 +47,6 @@ export function useEventStreamsActions(view: IEdaView) { isDanger: true, }, ], - [deleteEventStreams, pageNavigate, t] + [canCreateEventStream, deleteEventStreams, pageNavigate, t] ); }