Merge pull request #1578 from automatisch/AUT-620

feat: improve UI display depending on user permissions
This commit is contained in:
Ali BARIN
2024-06-20 12:04:31 +02:00
committed by GitHub
5 changed files with 145 additions and 76 deletions

View File

@@ -8,6 +8,7 @@ import * as URLS from 'config/urls';
import useFormatMessage from 'hooks/useFormatMessage'; import useFormatMessage from 'hooks/useFormatMessage';
import { ConnectionPropType } from 'propTypes/propTypes'; import { ConnectionPropType } from 'propTypes/propTypes';
import { useQueryClient } from '@tanstack/react-query'; import { useQueryClient } from '@tanstack/react-query';
import Can from 'components/Can';
function ContextMenu(props) { function ContextMenu(props) {
const { const {
@@ -44,34 +45,57 @@ function ContextMenu(props) {
hideBackdrop={false} hideBackdrop={false}
anchorEl={anchorEl} anchorEl={anchorEl}
> >
<MenuItem <Can I="read" a="Flow" passThrough>
component={Link} {(allowed) => (
to={URLS.APP_FLOWS_FOR_CONNECTION(appKey, connection.id)} <MenuItem
onClick={createActionHandler({ type: 'viewFlows' })} component={Link}
> to={URLS.APP_FLOWS_FOR_CONNECTION(appKey, connection.id)}
{formatMessage('connection.viewFlows')} onClick={createActionHandler({ type: 'viewFlows' })}
</MenuItem> disabled={!allowed}
>
<MenuItem onClick={createActionHandler({ type: 'test' })}> {formatMessage('connection.viewFlows')}
{formatMessage('connection.testConnection')} </MenuItem>
</MenuItem>
<MenuItem
component={Link}
disabled={disableReconnection}
to={URLS.APP_RECONNECT_CONNECTION(
appKey,
connection.id,
connection.appAuthClientId,
)} )}
onClick={createActionHandler({ type: 'reconnect' })} </Can>
>
{formatMessage('connection.reconnect')}
</MenuItem>
<MenuItem onClick={createActionHandler({ type: 'delete' })}> <Can I="update" a="Connection" passThrough>
{formatMessage('connection.delete')} {(allowed) => (
</MenuItem> <MenuItem
onClick={createActionHandler({ type: 'test' })}
disabled={!allowed}
>
{formatMessage('connection.testConnection')}
</MenuItem>
)}
</Can>
<Can I="create" a="Connection" passThrough>
{(allowed) => (
<MenuItem
component={Link}
disabled={!allowed || disableReconnection}
to={URLS.APP_RECONNECT_CONNECTION(
appKey,
connection.id,
connection.appAuthClientId,
)}
onClick={createActionHandler({ type: 'reconnect' })}
>
{formatMessage('connection.reconnect')}
</MenuItem>
)}
</Can>
<Can I="delete" a="Connection" passThrough>
{(allowed) => (
<MenuItem
onClick={createActionHandler({ type: 'delete' })}
disabled={!allowed}
>
{formatMessage('connection.delete')}
</MenuItem>
)}
</Can>
</Menu> </Menu>
); );
} }

View File

@@ -3,6 +3,7 @@ import PropTypes from 'prop-types';
import AppConnectionRow from 'components/AppConnectionRow'; import AppConnectionRow from 'components/AppConnectionRow';
import NoResultFound from 'components/NoResultFound'; import NoResultFound from 'components/NoResultFound';
import Can from 'components/Can';
import useFormatMessage from 'hooks/useFormatMessage'; import useFormatMessage from 'hooks/useFormatMessage';
import * as URLS from 'config/urls'; import * as URLS from 'config/urls';
import useAppConnections from 'hooks/useAppConnections'; import useAppConnections from 'hooks/useAppConnections';
@@ -16,11 +17,15 @@ function AppConnections(props) {
if (!hasConnections) { if (!hasConnections) {
return ( return (
<NoResultFound <Can I="create" a="Connection" passThrough>
to={URLS.APP_ADD_CONNECTION(appKey)} {(allowed) => (
text={formatMessage('app.noConnections')} <NoResultFound
data-test="connections-no-results" text={formatMessage('app.noConnections')}
/> data-test="connections-no-results"
{...(allowed && { to: URLS.APP_ADD_CONNECTION(appKey) })}
/>
)}
</Can>
); );
} }

View File

@@ -5,6 +5,7 @@ import PaginationItem from '@mui/material/PaginationItem';
import * as URLS from 'config/urls'; import * as URLS from 'config/urls';
import AppFlowRow from 'components/FlowRow'; import AppFlowRow from 'components/FlowRow';
import Can from 'components/Can';
import NoResultFound from 'components/NoResultFound'; import NoResultFound from 'components/NoResultFound';
import useFormatMessage from 'hooks/useFormatMessage'; import useFormatMessage from 'hooks/useFormatMessage';
import useConnectionFlows from 'hooks/useConnectionFlows'; import useConnectionFlows from 'hooks/useConnectionFlows';
@@ -36,11 +37,20 @@ function AppFlows(props) {
if (!hasFlows) { if (!hasFlows) {
return ( return (
<NoResultFound <Can I="create" a="Flow" passThrough>
to={URLS.CREATE_FLOW_WITH_APP_AND_CONNECTION(appKey, connectionId)} {(allowed) => (
text={formatMessage('app.noFlows')} <NoResultFound
data-test="flows-no-results" text={formatMessage('app.noFlows')}
/> data-test="flows-no-results"
{...(allowed && {
to: URLS.CREATE_FLOW_WITH_APP_AND_CONNECTION(
appKey,
connectionId
),
})}
/>
)}
</Can>
); );
} }

View File

@@ -30,6 +30,7 @@ import AppIcon from 'components/AppIcon';
import Container from 'components/Container'; import Container from 'components/Container';
import PageTitle from 'components/PageTitle'; import PageTitle from 'components/PageTitle';
import useApp from 'hooks/useApp'; import useApp from 'hooks/useApp';
import Can from 'components/Can';
const ReconnectConnection = (props) => { const ReconnectConnection = (props) => {
const { application, onClose } = props; const { application, onClose } = props;
@@ -92,7 +93,7 @@ export default function Application() {
} }
return options; return options;
}, [appKey, appConfig?.data, currentUserAbility]); }, [appKey, appConfig?.data, currentUserAbility, formatMessage]);
if (loading) return null; if (loading) return null;
@@ -118,37 +119,46 @@ export default function Application() {
<Route <Route
path={`${URLS.FLOWS}/*`} path={`${URLS.FLOWS}/*`}
element={ element={
<ConditionalIconButton <Can I="create" a="Flow" passThrough>
type="submit" {(allowed) => (
variant="contained" <ConditionalIconButton
color="primary" type="submit"
size="large" variant="contained"
component={Link} color="primary"
to={URLS.CREATE_FLOW_WITH_APP_AND_CONNECTION( size="large"
appKey, component={Link}
connectionId, to={URLS.CREATE_FLOW_WITH_APP_AND_CONNECTION(
appKey,
connectionId,
)}
fullWidth
icon={<AddIcon />}
disabled={!allowed}
>
{formatMessage('app.createFlow')}
</ConditionalIconButton>
)} )}
fullWidth </Can>
icon={<AddIcon />}
disabled={!currentUserAbility.can('create', 'Flow')}
>
{formatMessage('app.createFlow')}
</ConditionalIconButton>
} }
/> />
<Route <Route
path={`${URLS.CONNECTIONS}/*`} path={`${URLS.CONNECTIONS}/*`}
element={ element={
<SplitButton <Can I="create" a="Connection" passThrough>
disabled={ {(allowed) => (
(appConfig?.data && <SplitButton
!appConfig?.data?.canConnect && disabled={
!appConfig?.data?.canCustomConnect) || !allowed ||
connectionOptions.every(({ disabled }) => disabled) (appConfig?.data &&
} !appConfig?.data?.canConnect &&
options={connectionOptions} !appConfig?.data?.canCustomConnect) ||
/> connectionOptions.every(({ disabled }) => disabled)
}
options={connectionOptions}
/>
)}
</Can>
} }
/> />
</Routes> </Routes>
@@ -169,17 +179,20 @@ export default function Application() {
label={formatMessage('app.connections')} label={formatMessage('app.connections')}
to={URLS.APP_CONNECTIONS(appKey)} to={URLS.APP_CONNECTIONS(appKey)}
value={URLS.APP_CONNECTIONS_PATTERN} value={URLS.APP_CONNECTIONS_PATTERN}
disabled={!app.supportsConnections} disabled={
!currentUserAbility.can('read', 'Connection') ||
!app.supportsConnections
}
component={Link} component={Link}
data-test="connections-tab" data-test="connections-tab"
/> />
<Tab <Tab
label={formatMessage('app.flows')} label={formatMessage('app.flows')}
to={URLS.APP_FLOWS(appKey)} to={URLS.APP_FLOWS(appKey)}
value={URLS.APP_FLOWS_PATTERN} value={URLS.APP_FLOWS_PATTERN}
component={Link} component={Link}
data-test="flows-tab" data-test="flows-tab"
disabled={!currentUserAbility.can('read', 'Flow')}
/> />
</Tabs> </Tabs>
</Box> </Box>
@@ -187,14 +200,20 @@ export default function Application() {
<Routes> <Routes>
<Route <Route
path={`${URLS.FLOWS}/*`} path={`${URLS.FLOWS}/*`}
element={<AppFlows appKey={appKey} />} element={
<Can I="read" a="Flow">
<AppFlows appKey={appKey} />
</Can>
}
/> />
<Route <Route
path={`${URLS.CONNECTIONS}/*`} path={`${URLS.CONNECTIONS}/*`}
element={<AppConnections appKey={appKey} />} element={
<Can I="read" a="Connection">
<AppConnections appKey={appKey} />
</Can>
}
/> />
<Route <Route
path="/" path="/"
element={ element={
@@ -218,17 +237,24 @@ export default function Application() {
<Route <Route
path="/connections/add" path="/connections/add"
element={ element={
<AddAppConnection onClose={goToApplicationPage} application={app} /> <Can I="create" a="Connection">
<AddAppConnection
onClose={goToApplicationPage}
application={app}
/>
</Can>
} }
/> />
<Route <Route
path="/connections/:connectionId/reconnect" path="/connections/:connectionId/reconnect"
element={ element={
<ReconnectConnection <Can I="create" a="Connection">
application={app} <ReconnectConnection
onClose={goToApplicationPage} application={app}
/> onClose={goToApplicationPage}
/>
</Can>
} }
/> />
</Routes> </Routes>

View File

@@ -84,10 +84,14 @@ export default function Applications() {
)} )}
{!isLoading && !hasApps && ( {!isLoading && !hasApps && (
<NoResultFound <Can I="create" a="Connection" passThrough>
text={formatMessage('apps.noConnections')} {(allowed) => (
to={URLS.NEW_APP_CONNECTION} <NoResultFound
/> text={formatMessage('apps.noConnections')}
{...(allowed && { to: URLS.NEW_APP_CONNECTION })}
/>
)}
</Can>
)} )}
{!isLoading && {!isLoading &&