Loading capif_frontend/src/configs/queryHelpers.js 0 → 100644 +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 capif_frontend/src/pages/me/invokers/[id].js 0 → 100644 +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 capif_frontend/src/pages/me/invokers/index.js +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 Loading @@ -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, Loading Loading @@ -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> Loading Loading
capif_frontend/src/configs/queryHelpers.js 0 → 100644 +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
capif_frontend/src/pages/me/invokers/[id].js 0 → 100644 +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
capif_frontend/src/pages/me/invokers/index.js +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 Loading @@ -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, Loading Loading @@ -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> Loading