Commit 512281b1 authored by Alex Kakiris's avatar Alex Kakiris
Browse files

add invoker detail page with discover

parent 8c640a33
Loading
Loading
Loading
Loading
+15 −0
Changes for capif_frontend/src/configs/queryHelpers.js: 15 added lines, 0 removed lines.
Original line number Diff line number Diff line
// Client errors (e.g. 403, 404) won't change on retry; only retry server-side failures.
export const retryServerErrorsOnly = (failureCount, error) => {
  const status = error?.response?.status
  if (status && status < 500) return false

  return failureCount < 3
}

// Backend messages are deliberately generic, so show them with a fallback.
// With no response at all (backend unreachable), the fallback is shown.
export const errorMessage = (error, fallback) => {
  if (error?.response?.status === 403) return 'This account has no CAPIF credentials.'

  return error?.response?.data?.error || fallback
}
 No newline at end of file
+80 −0
Changes for capif_frontend/src/pages/me/invokers/[id].js: 80 added lines, 0 removed lines.
Original line number Diff line number Diff line
import Link from 'next/link'
import { useRouter } from 'next/router'
import Box from '@mui/material/Box'
import Button from '@mui/material/Button'
import Card from '@mui/material/Card'
import CardHeader from '@mui/material/CardHeader'
import CardContent from '@mui/material/CardContent'
import CircularProgress from '@mui/material/CircularProgress'
import Alert from '@mui/material/Alert'
import List from '@mui/material/List'
import ListItem from '@mui/material/ListItem'
import ListItemText from '@mui/material/ListItemText'
import Typography from '@mui/material/Typography'
import { useQuery } from '@tanstack/react-query'

import { discoverApis } from 'src/configs/apiService'
import { errorMessage, retryServerErrorsOnly } from 'src/configs/queryHelpers'

const ApiList = ({ invokerId }) => {
  const { data, isPending, isError, error } = useQuery({
    queryKey: ['invoker-apis', invokerId],
    queryFn: () => discoverApis(invokerId),
    enabled: Boolean(invokerId), // router.query is empty on the first render of a dynamic route
    retry: retryServerErrorsOnly
  })

  const apis = data?.serviceAPIDescriptions ?? []

  if (isPending) {
    return (
      <Box sx={{ display: 'flex', justifyContent: 'center', p: 4 }}>
        <CircularProgress />
      </Box>
    )
  }

  if (isError) {
    return <Alert severity='error'>{errorMessage(error, 'Could not load the APIs.')}</Alert>
  }

  if (apis.length === 0) {
    return <Typography>No APIs are available to this invoker yet.</Typography>
  }

  return (
    <List>
      {apis.map(api => (
        <ListItem key={api.apiId} disableGutters>
          <ListItemText primary={api.apiName} secondary={api.apiId} />
        </ListItem>
      ))}
    </List>
  )
}

const InvokerDetailPage = () => {
  const router = useRouter()
  const invokerId = typeof router.query.id === 'string' ? router.query.id : undefined

  return (
    <Box sx={{ p: 6 }}>
      <Button component={Link} href='/me/invokers' sx={{ mb: 4 }}>
        Back to invokers
      </Button>
      <Card>
        <CardHeader title={invokerId ?? ''} subheader='Available APIs' />
        <CardContent>
          <ApiList invokerId={invokerId} />
        </CardContent>
      </Card>
    </Box>
  )
}

InvokerDetailPage.acl = {
  action: 'read',
  subject: 'user-area'
}

export default InvokerDetailPage
 No newline at end of file
+6 −17
Changes for capif_frontend/src/pages/me/invokers/index.js: 6 added lines, 17 removed lines.
Original line number Diff line number Diff line
@@ -16,27 +16,14 @@ import DialogContent from '@mui/material/DialogContent'
import DialogActions from '@mui/material/DialogActions'
import TextField from '@mui/material/TextField'
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'

import { getMyInvokers, onboardInvoker } from 'src/configs/apiService'
import Link from 'next/link'
import ListItemButton from '@mui/material/ListItemButton'
import { errorMessage, retryServerErrorsOnly } from 'src/configs/queryHelpers'

const MY_INVOKERS_KEY = ['my-invokers']
const EMPTY_FORM = { apiInvokerInformation: '', notificationDestination: '' }

// Client errors (e.g. 403 no CAPIF credentials) won't change on retry; only retry server-side failures.
const retryServerErrorsOnly = (failureCount, error) => {
  const status = error?.response?.status
  if (status && status < 500) return false

  return failureCount < 3
}

// Backend messages are deliberately generic, so show them with a fallback.
const errorMessage = (error, fallback) => {
  if (error?.response?.status === 403) return 'This account has no CAPIF credentials.'

  return error?.response?.data?.error || fallback
}

const InvokerList = () => {
  const { data, isPending, isError, error } = useQuery({
    queryKey: MY_INVOKERS_KEY,
@@ -66,8 +53,10 @@ const InvokerList = () => {
  return (
    <List>
      {invokers.map(id => (
        <ListItem key={id} disableGutters>
        <ListItem key={id} disablePadding>
          <ListItemButton component={Link} href={`/me/invokers/${encodeURIComponent(id)}`}>
            <ListItemText primary={id} />
          </ListItemButton>
        </ListItem>
      ))}
    </List>