Commit bdec0753 authored by guillecxb's avatar guillecxb
Browse files

update every pages to new version in wich pagination and search is managed in frontend

parent 1ae57b9c
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -14,7 +14,7 @@ NEXT_PUBLIC_JWT_REFRESH_TOKEN_SECRET=7c4c1c50-3230-45bf-9eae-c9b2e401c767
# Peñuelas capif
# NEXT_PUBLIC_API_BASE_URL="https://backoffice.mobilesandbox.cloud:38443/api"

NEXT_PUBLIC_API_BASE_URL="http://localhost:8085/api"
NEXT_PUBLIC_API_BASE_URL="https://backoffice.mobilesandbox.cloud:38443/api"

NEXT_PUBLIC_GRAFANA_BASE_URL="https://grafana.5gnacar.int"
NODE_ENV=development
+141 −46
Original line number Diff line number Diff line
@@ -10,22 +10,73 @@ export const getInvokers = async () => {
}

// GET invokers with pagination and date order
export const getInvokersPagesOrder = async ({ page, pageSize, order }) => {
export const getInvokersPagesOrder = async () => {
  try {
    const response = await axiosInstance.get(`/invokers/`, {
    const response = await axiosInstance.get(`/invokers/total`);

    return response;
  } catch (error) {
    throw new Error(`Error fetching invokers: ${error.message}`);
  }
}

export const getInvokerInformation = async invoker_id => {
  try {
    const response = await axiosInstance.get(`/invokers/alone`, {
      params: {
        page: page,
        pageSize: pageSize,
        order: order
        invoker_id: invoker_id,
      }
    });
    
    return response.data;
  } catch (error) {
    throw new Error(`Error fetching invokers: ${error.message}`);
    throw new Error(`Error fetching invoker information: ${error.message}`);
  }
}

export const getProviderInformation = async api_prov_dom_id => {
  try {
    const response = await axiosInstance.get(`/providers/alone`, {
      params: {
        api_prov_dom_id: api_prov_dom_id,
      }
    });
    
    return response.data;
  } catch (error) {
    throw new Error(`Error fetching provider information: ${error.message}`);
  }
}

export const getApisOfProvider = async apf_id => {
  try {
    const response = await axiosInstance.get(`/apis/provider`, {
      params: {
        apf_id: apf_id,
      }
    });
    
    return response.data;
  } catch (error) {
    throw new Error(`Error fetching provider apis: ${error.message}`);
  }
}

export const getInvokerSecurityContext = async invoker_id => {
  try {
    const response = await axiosInstance.get(`/invokers/security`, {
      params: {
        invoker_id: invoker_id,
      }
    });
    
    return response.data;
  } catch (error) {
    throw new Error(`Error fetching invoker's security context: ${error.message}`);
  }
}


// GET the num of invokers in the database
export const getNumInvokers = async () => {
  return axiosInstance.get(`/invokers/numInvokers`)
@@ -69,17 +120,12 @@ export const getProviders = async () => {
  return axiosInstance.get(`/providers/providersTotal`)
}

export const getProvidersPagesOrder = async ({ page, pageSize, order }) => {
export const getProvidersPagesOrder = async () => {
  try {
    const response = await axiosInstance.get(`/providers/`, {
      params: {
        page: page,
        pageSize: pageSize,
        order: order
      }
    });
    
    return response.data;
    return response;
  } catch (error) {
    throw new Error(`Error fetching providers: ${error.message}`);
  }
@@ -128,49 +174,104 @@ export const getApis = async () => {
  return axiosInstance.get(`/apis/apisTotal`)
}

export const getApiInformation = async api_id => {
  try {
    const response = await axiosInstance.get(`/apis/alone`, {
      params: {
        api_id: api_id,
      }
    });
    
    return response.data;
  } catch (error) {
    throw new Error(`Error fetching api information: ${error.message}`);
  }
}


// GET num of apis in the database
export const getNumApis = async () => {
  return axiosInstance.get(`/apis/num`)
}

// GEt apis with pagination and date order
export const getApisPagesOrder = async ({ page, pageSize, order }) => {
export const getApisPagesOrder = async () => {
  try {
    const response = await axiosInstance.get(`/apis/`, {
      params: {
        page: page,
        pageSize: pageSize,
        order: order
      }
    });
    const response = await axiosInstance.get(`/apis/`);

    return response.data;
    return response;
  } catch (error) {
    throw new Error(`Error fetching apis: ${error.message}`);
  }
}

// export const deleteProvidersServices = async (selectedApis) => {
//   try {
//     // Asegúrate de que el body envíe las APIs seleccionadas correctamente
//     const response = await axiosInstance.delete('/apis/', {
//       data: {
//         api: selectedApis,
//       },
//     });
//     return response.data;
//   } catch (error) {
//     console.error('Error deleting APIs:', error);
//     throw error;
//   }
// };

// DELETE multiple apis
export const deleteProvidersServices = async apis => {
export const deleteProvidersServices = async (selectedApis) => {
  try {
    const data = {
      api: apis.map(({ apf_id, api_id }) => ({ apf_id, api_id }))
    };

    const response = await axiosInstance.delete('/apis/', {
      headers: {
        'Content-Type': 'application/json'
      },
      data: JSON.stringify(data)
      data: { api: selectedApis }
    });
    
    return response.data; // Retorna los datos de la respuesta si la solicitud fue exitosa
    return response.data;
  } catch (error) {
    throw error; // Lanza un error si la solicitud no fue exitosa
    console.error('Error deleting APIs:', error);
    throw error;
  }
};

// DELETE multiple apis
// export const deleteProvidersServices = async apis => {
//   try {
//     const data = {
//       api: apis.map(({ apf_id, api_id }) => ({ apf_id, api_id }))
//     };

//     const response = await axiosInstance.delete('/apis/', {
//       headers: {
//         'Content-Type': 'application/json'
//       },
//       data: {
//         api: selectedApis,
//       },
//     });

//     return response.data; // Retorna los datos de la respuesta si la solicitud fue exitosa
//   } catch (error) {
//     throw error; // Lanza un error si la solicitud no fue exitosa
//   }
// };

// DELETE multiple apis
// const deleteApis = async (selectedApis) => {
//   try {
//     const response = await axiosInstance.delete('/apis/', {
      // data: {
      //   api: selectedApis,
      // },
//     });

//     return response.data;
//   } catch (error) {
//     console.error('Error deleting APIs:', error.response ? error.response.data : error.message);
//     throw error;
//   }
// };





@@ -187,17 +288,11 @@ export const getUsers = async () => {
  return response.data;  // Devolver solo los datos relevantes
};

export const getUsersPagesOrder = async ({ page, pageSize, order }) => {
export const getUsersPagesOrder = async () => {
  try {
    const response = await axiosInstance.get(`/users/`, {
      params: {
        page: page,
        pageSize: pageSize,
        order: order
      }
    });
    const response = await axiosInstance.get(`/users/`);
    
    return response.data;
    return response;
  } catch (error) {
    throw new Error(`Error fetching users: ${error.message}`);
  }
+89 −59
Original line number Diff line number Diff line
@@ -4,16 +4,12 @@ import Card from '@mui/material/Card'
import Typography from '@mui/material/Typography'
import CardHeader from '@mui/material/CardHeader'
import PageHeader from 'src/@core/components/page-header'
import Table from '@mui/material/Table'
import TableContainer from '@mui/material/TableContainer'
import CardContent from '@mui/material/CardContent'
import { useRouter } from 'next/router'
import { styled } from '@mui/material/styles'
import { getApis } from 'src/configs/apiService'
import { use, useEffect, useState } from 'react'
import { useQuery, useQueryClient } from '@tanstack/react-query'
import { set } from 'nprogress'

import { getApiInformation } from 'src/configs/apiService'
import { useEffect, useState } from 'react'
import Box from '@mui/material/Box'

const LinkStyled = styled(Link)(({ theme }) => ({
  textDecoration: 'none',
@@ -22,74 +18,108 @@ const LinkStyled = styled(Link)(({ theme }) => ({

const Apis = () => {
  const router = useRouter()
  const apiName = router.query.id
  const api_id = router.query.id
  const [selectedApi, setSelectedApi] = useState(null);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);

  // Define la clave única para esta consulta
  const queryKey = ['apis'];

  // Usa useQuery para obtener los datos
  const { data: apisData, isLoading, isError, refetch } = useQuery({
    queryKey,
    queryFn: getApis,
  });

  const selectApi = () => {
  // Fetch API information
  useEffect(() => {
    if (api_id) {
      const fetchApiInformation = async () => {
        setLoading(true);
        setError(null);
        try {
      if (Array.isArray(apisData.data.object)) {
        // Filtra el array para encontrar el elemento deseado
        const selectedApi = apisData.data.object.find(api => api.api_name === apiName);
        setSelectedApi(selectedApi);
  
        if (selectedApi) {
          console.log('Selected API:', selectedApi);
          // Realiza acciones con el elemento seleccionado
        } else {
          console.warn('API not found:', apiName);
        }
      } else {
        console.error('Error: apisData is not an array');
        console.error('apisData:', apisData);
      }
    } catch (error) {
      console.error('Error fetching data:', error);
          const apiData = await getApiInformation(api_id); // Llamada a la API
          setSelectedApi(apiData[0]); // Almacenar el primer elemento (asumiendo que devuelve un array)
        } catch (err) {
          setError("Error fetching API information");
          console.error(err);
        } finally {
          setLoading(false);
        }
      };

  useEffect(() => {
    selectApi();
  }, [apiName, apisData]); 


      fetchApiInformation();
    }
  }, [api_id]);

  if (loading) return <Typography>Loading...</Typography>;
  if (error) return <Typography color="error">{error}</Typography>;

  return (
    <Grid container spacing={6}>
      <PageHeader title={<Typography variant='h5'>API: {apiName} </Typography>} />
      <PageHeader title={<Typography variant='h5'>API: {api_id} </Typography>} />

      <Grid item xs={12}>
        <Card>
          <CardHeader title='Information' />
          <CardContent>
            <p>
                Nombre: {apiName}
            </p>
            <p>
                API: {selectedApi?.api_id}
            </p>
            <p>
                APF: {selectedApi?.apf_id}
            </p>
            <p>
                AEF: {selectedApi?.aef_profiles[0].aef_id}
            </p>
            {selectedApi ? (
              <Grid container spacing={2}>
                {/* Display API General Information */}
                <Grid item xs={12} mt={4}>
                  <Typography variant="h6" gutterBottom><strong>General Information</strong></Typography>
                  <Box mt={2}>
                    <Typography><strong>API Name:</strong> {selectedApi.api_name}</Typography>
                    <Typography><strong>API ID:</strong> {selectedApi.api_id}</Typography>
                    <Typography><strong>Description:</strong> {selectedApi.description}</Typography>
                    <Typography><strong>Onboarding Date:</strong> {selectedApi.onboarding_date}</Typography>
                    <Typography><strong>Service API Category:</strong> {selectedApi.service_api_category || 'N/A'}</Typography>
                    <Typography><strong>Supported Features:</strong> {selectedApi.supported_features}</Typography>
                  </Box>
                </Grid>

                {/* Display AEF Profiles */}
                <Grid item xs={12} mt={6}>
                  <Typography variant="h6" gutterBottom><strong>AEF Profiles</strong></Typography>
                  {selectedApi.aef_profiles.map((profile, index) => (
                    <Box key={profile.aef_id} mb={4} mt={4}>
                      <Typography><strong>AEF ID:</strong> {profile.aef_id}</Typography>
                      <Typography><strong>Data Format:</strong> {profile.data_format}</Typography>
                      <Typography><strong>Protocol:</strong> {profile.protocol}</Typography>

                      {/* Interface Descriptions */}
                      <Typography variant="h6" mt={4} gutterBottom><strong>Interface Descriptions</strong></Typography>
                      {profile.interface_descriptions.map((desc, idx) => (
                        <Box key={idx} mb={2} mt={2}>
                          <Typography><strong>IPv4 Address:</strong> {desc.ipv4_addr}</Typography>
                          <Typography><strong>Port:</strong> {desc.port}</Typography>
                          <Typography><strong>Security Methods:</strong> {desc.security_methods.join(", ")}</Typography>
                        </Box>
                      ))}

                      {/* API Versions */}
                      <Typography variant="h6" mt={4} gutterBottom><strong>Versions</strong></Typography>
                      {profile.versions.map((version, idx) => (
                        <Box key={idx} mb={4} mt={2}>
                          <Typography><strong>API Version:</strong> {version.api_version}</Typography>
                          <Typography><strong>Expiry:</strong> {version.expiry}</Typography>

                          {/* Resources */}
                          <Typography variant="h6" mt={4} gutterBottom><strong>Resources</strong></Typography>
                          {version.resources.map((resource, idx) => (
                            <Box key={idx} mb={2} mt={2}>
                              <Typography><strong>Resource Name:</strong> {resource.resource_name}</Typography>
                              <Typography><strong>URI:</strong> {resource.uri}</Typography>
                              <Typography><strong>Operations:</strong> {resource.operations.join(", ")}</Typography>
                              <Typography><strong>Description:</strong> {resource.description}</Typography>
                            </Box>
                          ))}
                        </Box>
                      ))}
                    </Box>
                  ))}
                </Grid>
              </Grid>
            ) : (
              <Typography>No API data available.</Typography>
            )}
          </CardContent>
        </Card>
      </Grid>
    </Grid>

    
  )
}

export default Apis
export default Apis;
+82 −97
Original line number Diff line number Diff line
import React, { useState, useEffect } from 'react';
import { useQuery, useQueryClient } from '@tanstack/react-query';
import { getApisPagesOrder, deleteProvidersServices, searchApis } from 'src/configs/apiService';
import Link from 'next/link';
import { styled } from '@mui/material/styles';
import {
@@ -27,6 +26,7 @@ import {
  DialogContent,
  DialogActions,
} from '@mui/material';
import { getApisPagesOrder, deleteProvidersServices } from 'src/configs/apiService';
import ArrowDropDownIcon from '@mui/icons-material/ArrowDropDown';
import ArrowDropUpIcon from '@mui/icons-material/ArrowDropUp';

@@ -37,8 +37,6 @@ const LinkStyled = styled(Link)(({ theme }) => ({

const Apis = () => {
  const queryClient = useQueryClient();
  const [selectedApis, setSelectedApis] = useState([]);
  const [isDeleteDialogOpen, setDeleteDialogOpen] = useState(false);
  const [currentPage, setCurrentPage] = useState(1);
  const [pageSize, setPageSize] = useState(10);
  const [totalPages, setTotalPages] = useState(0);
@@ -46,106 +44,101 @@ const Apis = () => {
  const [apis, setApis] = useState([]);
  const [paginatedApis, setPaginatedApis] = useState([]);
  const [searchTerm, setSearchTerm] = useState('');
  const [selectedApis, setSelectedApis] = useState([]);
  const [sortOrder, setSortOrder] = useState('asc');
  const [isAscending, setIsAscending] = useState(true);
  const [isDeleteDialogOpen, setIsDeleteDialogOpen] = useState(false);
  const [isDeleting, setIsDeleting] = useState(false);
  const [showDeleteMessage, setShowDeleteMessage] = useState(false);
  const [errorDeleting, setErrorDeleting] = useState(false);
  const [deleteMessage, setDeleteMessage] = useState('');

  // Obtener todos los datos de APIs
  const { data: apisData, isLoading, isError } = useQuery({
  const { data: apisData, isLoading, isError, refetch } = useQuery({
    queryKey: ['apis'],
    queryFn: () => getApisPagesOrder({ page: 1, pageSize: 1000 }), // Obtener todos los datos
    queryFn: getApisPagesOrder, // Obtener todos los datos
  });

  useEffect(() => {
    if (apisData) {
      setApis(apisData.data);
      setTotalApis(apisData.total);
      setTotalPages(Math.ceil(apisData.data.length / pageSize));
      // Paginar los datos
    if (apisData && Array.isArray(apisData.data)) {
      let filteredApis = apisData.data;

      // Aplicar filtro de búsqueda por api_id o api_name
      if (searchTerm) {
        filteredApis = filteredApis.filter((api) =>
          api.api_id.toLowerCase().includes(searchTerm.toLowerCase()) ||
          api.api_name?.toLowerCase().includes(searchTerm.toLowerCase())
        );
      }

      // Aplicar orden por fecha
      filteredApis.sort((a, b) => {
        const dateA = new Date(a.onboarding_date);
        const dateB = new Date(b.onboarding_date);
        
        return isAscending ? dateA - dateB : dateB - dateA;
      });

      setTotalApis(filteredApis.length || 0);
      setTotalPages(Math.ceil(filteredApis.length / pageSize));

      const start = (currentPage - 1) * pageSize;
      const end = start + pageSize;
      setPaginatedApis(apisData.data.slice(start, end));
      setPaginatedApis(filteredApis.slice(start, end));
    }
  }, [apisData, currentPage, pageSize]);
  }, [apisData, currentPage, pageSize, searchTerm, isAscending]);

  const handleToggleApi = (apf_id, api_id) => {
    const selectedIndex = selectedApis.findIndex(api => api.api_id === api_id);
  const handleToggleApi = (apiId, apfId) => {
    const selectedIndex = selectedApis.findIndex((api) => api.api_id === apiId); // Buscar por api_id
    let newSelected = [];

    if (selectedIndex === -1) {
      newSelected = [...selectedApis, { apf_id, api_id }];
      newSelected = newSelected.concat(selectedApis, { api_id: apiId, apf_id: apfId });
    } else if (selectedIndex === 0) {
      newSelected = selectedApis.slice(1);
      newSelected = newSelected.concat(selectedApis.slice(1));
    } else if (selectedIndex === selectedApis.length - 1) {
      newSelected = selectedApis.slice(0, -1);
      newSelected = newSelected.concat(selectedApis.slice(0, -1));
    } else if (selectedIndex > 0) {
      newSelected = [
        ...selectedApis.slice(0, selectedIndex),
        ...selectedApis.slice(selectedIndex + 1),
      ];
      newSelected = newSelected.concat(
        selectedApis.slice(0, selectedIndex),
        selectedApis.slice(selectedIndex + 1)
      );
    }
    setSelectedApis(newSelected);
  };

  const handleDeleteClick = () => {
    setDeleteDialogOpen(true);
  const handlePageChange = (event, newPage) => {
    setCurrentPage(newPage);
  };

  const handleDeleteConfirm = async () => {
    try {
      setIsDeleting(true);
      setErrorDeleting(false);
  const handlePageSizeChange = (event) => {
    const newSize = event.target.value;
    setPageSize(newSize);
    setCurrentPage(1); // Reiniciar a la primera página cuando se cambie el tamaño de las filas
  };

      await deleteProvidersServices(selectedApis);
  const handleClickDate = () => {
    setIsAscending((prevState) => !prevState); // Alternar el estado de orden
  };

      setDeleteMessage('APIs removed');
      // Refrescar la lista de APIs
      const response = await getApisPagesOrder({ page: currentPage, pageSize, order: sortOrder });
      setApis(response.data);
      setTotalApis(response.total);
      setTotalPages(Math.ceil(response.total / pageSize));
  const handleDeleteClick = () => {
    setIsDeleteDialogOpen(true);
  };

      setDeleteDialogOpen(false);
      setSelectedApis([]);
      setShowDeleteMessage(true);
  const handleDeleteConfirm = async () => {
    setIsDeleting(true);
    try {
      await deleteProvidersServices(selectedApis); // Llamada para eliminar APIs
      console.log('APIs deleted:', selectedApis);
      setIsDeleteDialogOpen(false); // Cerrar el diálogo
      setSelectedApis([]); // Vaciar la selección
      refetch(); // Refrescar la lista de APIs
    } catch (error) {
      setErrorDeleting(true);
      console.error('Error deleting APIs:', error);
    } finally {
      setIsDeleting(false);
    }
  };

  const handleDeleteCancel = () => {
    setDeleteDialogOpen(false);
  };

  const handleDeleteMessageAccept = () => {
    setShowDeleteMessage(false);
  };

  const handlePageChange = (event, newPage) => {
    setCurrentPage(newPage);
    const start = (newPage - 1) * pageSize;
    const end = start + pageSize;
    setPaginatedApis(apis.slice(start, end));
  };

  const handlePageSizeChange = (event) => {
    const newSize = event.target.value;
    setPageSize(newSize);
    setCurrentPage(1);
    const start = 0;
    const end = newSize;
    setPaginatedApis(apis.slice(start, end));
    setTotalPages(Math.ceil(apis.length / newSize));
  };

  const handleClickDate = () => {
    setIsAscending((prevState) => !prevState);
    setSortOrder(sortOrder === 'asc' ? 'desc' : 'asc');
    setIsDeleteDialogOpen(false); // Cerrar el cuadro de diálogo sin hacer nada
  };

  if (isLoading) return <CircularProgress />;
@@ -164,17 +157,13 @@ const Apis = () => {
            <Grid container spacing={2} alignItems="center" justifyContent="flex-end">
              <Grid item>
                <TextField
                  label="Search by ..."
                  label="Search by ID or Name"
                  variant="outlined"
                  value={searchTerm}
                  onChange={(e) => setSearchTerm(e.target.value)}
                  sx={{ width: '300px' }}
                />
              </Grid>
              <Grid item>
                <Button variant="contained" color="primary">
                  Search
                </Button>
              </Grid>
            </Grid>
          </Grid>
        </Grid>
@@ -204,17 +193,15 @@ const Apis = () => {
                  <TableRow key={api.api_id}>
                    <TableCell>
                      <Checkbox
                        onChange={() => handleToggleApi(api.apf_id, api.api_id)}
                        checked={selectedApis.some(
                          (selected) => selected.api_id === api.api_id && selected.apf_id === api.apf_id
                        )}
                        onChange={() => handleToggleApi(api.api_id, api.apf_id)} // Pasar api_id y apf_id
                        checked={selectedApis.some((selected) => selected.api_id === api.api_id)} // Comprobar si está seleccionado
                      />
                    </TableCell>
                    <TableCell>
                      <LinkStyled href={`/apis/${api.api_name}`}>{api.api_name}</LinkStyled>
                      <LinkStyled href={`/apis/${api.api_id}`}>{api.api_name}</LinkStyled>
                    </TableCell>
                    <TableCell>{api.description}</TableCell>
                    <TableCell>{api.aef_profiles[0].aef_id}</TableCell>
                    <TableCell>{api.aef_profiles[0]?.aef_id}</TableCell>
                    <TableCell>{api.onboarding_date}</TableCell>
                  </TableRow>
                ))}
@@ -230,9 +217,14 @@ const Apis = () => {
            <Pagination count={totalPages} page={currentPage} onChange={handlePageChange} />
          </Grid>

          <Grid>
            <Button variant="contained" color="primary" onClick={handleDeleteClick}>
              Delete
          {/* Botón para eliminar */}
          <Grid item>
            <Button
              variant="contained"
              onClick={handleDeleteClick}
              disabled={selectedApis.length === 0} // Deshabilitar si no hay selección
            >
              Delete Selected
            </Button>
          </Grid>

@@ -246,10 +238,11 @@ const Apis = () => {
        </Grid>
      </Grid>

      {/* Cuadro de diálogo de confirmación de eliminación */}
      <Dialog open={isDeleteDialogOpen} onClose={handleDeleteCancel}>
        <DialogTitle>Confirm Deletion</DialogTitle>
        <DialogContent>
          Are you sure you want to delete the following APIs?
          <Typography>Are you sure you want to delete the following APIs?</Typography>
          <ul>
            {selectedApis.map((api) => (
              <li key={api.api_id}>{api.api_id}</li>
@@ -258,23 +251,15 @@ const Apis = () => {
        </DialogContent>
        <DialogActions>
          <Button onClick={handleDeleteCancel}>Cancel</Button>
          <Button onClick={handleDeleteConfirm} autoFocus disabled={isDeleting}>
          <Button
            onClick={handleDeleteConfirm}
            color="error"
            disabled={isDeleting} // Deshabilitar mientras se realiza la eliminación
          >
            {isDeleting ? <CircularProgress size={24} /> : 'Confirm'}
          </Button>
        </DialogActions>
      </Dialog>

      <Dialog open={showDeleteMessage} onClose={handleDeleteMessageAccept}>
        <DialogTitle>{errorDeleting ? 'Error Deleting API' : 'API Deleted!'}</DialogTitle>
        <DialogContent>
          {errorDeleting ? 'An error occurred while deleting the API.' : 'The APIs have been successfully deleted.'}
        </DialogContent>
        <DialogActions>
          <Button onClick={handleDeleteMessageAccept} autoFocus>
            Accept
          </Button>
        </DialogActions>
      </Dialog>
    </Grid>
  );
};
+216 −145

File changed.

Preview size limit exceeded, changes collapsed.

Loading