Merge pull request 'Added a lot of fixes' (#73) from more-fixes into main
Some checks failed
checks-impure / test (push) Successful in 26s
checks / test (push) Successful in 1m14s
assets1 / test (push) Has been cancelled

Reviewed-on: #73
This commit was merged in pull request #73.
This commit is contained in:
Sara Pervana
2024-01-26 01:25:58 +01:00
16 changed files with 271 additions and 161 deletions

View File

@@ -6,13 +6,15 @@ import { useGetAllRepositories } from "@/api/repositories/repositories";
import SummaryDetails from "@/components/summary_card"; import SummaryDetails from "@/components/summary_card";
import CustomTable from "@/components/table"; import CustomTable from "@/components/table";
import { import {
APSummaryDetails,
APAttachmentsTableConfig, APAttachmentsTableConfig,
APServiceRepositoryTableConfig, APServiceRepositoryTableConfig,
} from "@/config/access_point"; } from "@/config/access_point";
import { useEffect } from "react"; import { useEffect } from "react";
import useGetEntityByNameOrDid from "@/components/hooks/useGetEntityByNameOrDid";
import { projectConfig } from "@/config/config";
export default function AccessPoint() { export default function AccessPoint() {
const { entity } = useGetEntityByNameOrDid("AP");
const { const {
data: APAttachementData, data: APAttachementData,
isLoading: loadingAttachements, isLoading: loadingAttachements,
@@ -45,7 +47,7 @@ export default function AccessPoint() {
useEffect(() => { useEffect(() => {
const interval = setInterval(() => { const interval = setInterval(() => {
onRefresh(); onRefresh();
}, 5000); }, projectConfig.REFRESH_FREQUENCY);
return () => clearInterval(interval); return () => clearInterval(interval);
// eslint-disable-next-line react-hooks/exhaustive-deps // eslint-disable-next-line react-hooks/exhaustive-deps
@@ -54,10 +56,25 @@ export default function AccessPoint() {
return ( return (
<div className="m-10"> <div className="m-10">
<SummaryDetails <SummaryDetails
fake
hasRefreshButton hasRefreshButton
onRefresh={onRefresh} onRefresh={onRefresh}
entity={{ name: "Access Point", details: APSummaryDetails }} entity={{
name: "Access Point",
details: [
{
label: "DID",
value: entity?.did,
},
{
label: "IP",
value: entity?.ip,
},
{
label: "Network",
value: entity?.network,
},
],
}}
/> />
<div> <div>
<h4>Attachment View</h4> <h4>Attachment View</h4>

View File

@@ -1,19 +1,14 @@
"use client"; "use client";
import { useEffect, useMemo, useRef, useState } from "react"; import { useEffect, useMemo, useState } from "react";
import { ClientTableConfig, ServiceTableConfig } from "@/config/client_1"; import { ClientTableConfig, ServiceTableConfig } from "@/config/client_1";
import CustomTable from "@/components/table"; import CustomTable from "@/components/table";
import { import {
Alert, Alert,
Button, Button,
Card,
CardContent,
CardHeader,
Snackbar, Snackbar,
Typography,
CircularProgress, CircularProgress,
IconButton, IconButton,
} from "@mui/material"; } from "@mui/material";
import CopyToClipboard from "@/components/copy_to_clipboard";
import { import {
attachEntity, attachEntity,
detachEntity, detachEntity,
@@ -27,6 +22,8 @@ import { useGetAllServices } from "@/api/services/services";
import axios from "axios"; import axios from "axios";
import CloseIcon from "@mui/icons-material/Close"; import CloseIcon from "@mui/icons-material/Close";
import { useSearchParams } from "next/navigation"; import { useSearchParams } from "next/navigation";
import SummaryDetails from "@/components/summary_card";
import { projectConfig } from "@/config/config";
interface SnackMessage { interface SnackMessage {
message: string; message: string;
@@ -136,13 +133,12 @@ export default function Client() {
useEffect(() => { useEffect(() => {
const interval = setInterval(() => { const interval = setInterval(() => {
onRefresh(); onRefresh();
}, 5000); }, projectConfig.REFRESH_FREQUENCY);
return () => clearInterval(interval); return () => clearInterval(interval);
// eslint-disable-next-line react-hooks/exhaustive-deps // eslint-disable-next-line react-hooks/exhaustive-deps
}, []); }, []);
const cardContentRef = useRef<HTMLDivElement>(null);
const [snackbarOpen, setSnackbarOpen] = useState(false); const [snackbarOpen, setSnackbarOpen] = useState(false);
const [snackbarMessage, setSnackbarMessage] = useState< const [snackbarMessage, setSnackbarMessage] = useState<
SnackMessage | undefined SnackMessage | undefined
@@ -153,8 +149,6 @@ export default function Client() {
setSnackbarOpen(false); setSnackbarOpen(false);
}; };
console.log("entity", entity);
if (services_loading) return <Skeleton height={500} />; if (services_loading) return <Skeleton height={500} />;
if (!services) return <Alert severity="error">Client not found</Alert>; if (!services) return <Alert severity="error">Client not found</Alert>;
@@ -181,23 +175,16 @@ export default function Client() {
</div> </div>
</div> </div>
<Card variant="outlined"> <SummaryDetails
<CardHeader entity={{
subheader="Summary" name: "",
action={<CopyToClipboard contentRef={cardContentRef} />} details: [
/> { label: "DID", value: entity?.did },
<CardContent ref={cardContentRef}> { label: "IP", value: entity?.ip },
<Typography color="text.primary" gutterBottom> { label: "Network", value: entity?.network },
DID: <code>{entity?.did}</code> ],
</Typography> }}
<Typography color="text.primary" gutterBottom> />
IP: <code>{entity?.ip}</code>
</Typography>
<Typography color="text.primary" gutterBottom>
Network: <code>{entity?.network}</code>
</Typography>
</CardContent>
</Card>
<div> <div>
<h4>Client View</h4> <h4>Client View</h4>
<CustomTable <CustomTable

View File

@@ -1,13 +1,16 @@
"use client"; "use client";
import { DLGResolutionTableConfig, DLGSummaryDetails } from "@/config/dlg"; import { DLGResolutionTableConfig } from "@/config/dlg";
import CustomTable from "@/components/table"; import CustomTable from "@/components/table";
import SummaryDetails from "@/components/summary_card"; import SummaryDetails from "@/components/summary_card";
import { useEffect } from "react"; import { useEffect } from "react";
import { useGetAllResolutions } from "@/api/resolution/resolution"; import { useGetAllResolutions } from "@/api/resolution/resolution";
import { mutate } from "swr"; import { mutate } from "swr";
import useGetEntityByNameOrDid from "@/components/hooks/useGetEntityByNameOrDid";
import { projectConfig } from "@/config/config";
export default function DLG() { export default function DLG() {
const { entity } = useGetEntityByNameOrDid("DLG");
const { const {
data: resolutionData, data: resolutionData,
isLoading: loadingResolutions, isLoading: loadingResolutions,
@@ -28,7 +31,7 @@ export default function DLG() {
useEffect(() => { useEffect(() => {
const interval = setInterval(() => { const interval = setInterval(() => {
onRefresh(); onRefresh();
}, 5000); }, projectConfig.REFRESH_FREQUENCY);
return () => clearInterval(interval); return () => clearInterval(interval);
// eslint-disable-next-line react-hooks/exhaustive-deps // eslint-disable-next-line react-hooks/exhaustive-deps
@@ -37,12 +40,24 @@ export default function DLG() {
return ( return (
<div className="m-10"> <div className="m-10">
<SummaryDetails <SummaryDetails
fake
hasRefreshButton hasRefreshButton
onRefresh={onRefresh} onRefresh={onRefresh}
entity={{ entity={{
name: "Distributed Ledger Gateway", name: "Distributed Ledger Gateway",
details: DLGSummaryDetails, details: [
{
label: "DID",
value: entity?.did,
},
{
label: "IP",
value: entity?.ip,
},
{
label: "Network",
value: entity?.network,
},
],
}} }}
/> />
<div> <div>

View File

@@ -8,6 +8,7 @@ import dynamic from "next/dynamic";
import { useEffect } from "react"; import { useEffect } from "react";
import { mutate } from "swr"; import { mutate } from "swr";
import ErrorBoundary from "@/components/error_boundary"; import ErrorBoundary from "@/components/error_boundary";
import { projectConfig } from "@/config/config";
const NoSSRSequenceDiagram = dynamic( const NoSSRSequenceDiagram = dynamic(
() => import("../../components/sequence_diagram"), () => import("../../components/sequence_diagram"),
@@ -30,7 +31,7 @@ export default function Home() {
useEffect(() => { useEffect(() => {
const interval = setInterval(() => { const interval = setInterval(() => {
onRefresh(); onRefresh();
}, 5000); }, projectConfig.REFRESH_FREQUENCY);
return () => clearInterval(interval); return () => clearInterval(interval);
// eslint-disable-next-line react-hooks/exhaustive-deps // eslint-disable-next-line react-hooks/exhaustive-deps

View File

@@ -0,0 +1,111 @@
import { IEntityActions } from "@/types";
import { Button, Snackbar, Alert, AlertColor } from "@mui/material";
import { useState } from "react";
import useAxios from "../hooks/useAxios";
import { deleteEntity } from "@/api/entities/entities";
interface Props {
endpointData: IEntityActions[];
rowData?: any;
}
const SNACKBAR_DEFAULT = {
open: false,
message: "",
severity: "info" as AlertColor,
};
const EntityActions = ({ endpointData, rowData }: Props) => {
const [currentEndpoint, setCurrentEndpoint] = useState("");
const [shouldFetch, setShouldFetch] = useState(false);
const { error } = useAxios(currentEndpoint, "GET", null, true, shouldFetch);
const [snackbar, setSnackbar] = useState<{
open: boolean;
message: string;
severity: AlertColor;
}>(SNACKBAR_DEFAULT);
console.error("Error registering/deregistering:", error);
const onDeleteEntity = async () => {
if (rowData)
try {
const response = await deleteEntity({
entity_did: rowData?.entity_did,
});
console.log("On Delete:", response.data.message);
setSnackbar({
open: true,
message: response.data.message,
severity: "success",
});
} catch (error) {
console.error("Error deleting entity: ", error);
setSnackbar({
open: true,
message: "Failed to delete entity.",
severity: "error",
});
}
};
const onRegisterEntity = (endpoint: string) => {
setCurrentEndpoint(endpoint);
setShouldFetch(true);
};
const onDeregisterEntity = (endpoint: string) => {
setCurrentEndpoint(endpoint);
setShouldFetch(true);
};
const handleCloseSnackbar = () => {
setSnackbar(SNACKBAR_DEFAULT);
};
return (
<>
<div className="flex justify-between">
{endpointData.map(
({ name, endpoint }: IEntityActions, index: number) => {
const isRegister = name && name.toLocaleLowerCase() === "register";
return (
<Button
key={index}
onClick={() =>
isRegister
? onRegisterEntity(endpoint)
: onDeregisterEntity(endpoint)
}
variant="contained"
size="small"
>
{name}
</Button>
);
},
)}
<Button onClick={onDeleteEntity} size="small" variant="contained">
Delete
</Button>
</div>
<Snackbar
anchorOrigin={{ vertical: "top", horizontal: "center" }}
open={snackbar.open}
autoHideDuration={5000}
onClose={handleCloseSnackbar}
>
<Alert
onClose={handleCloseSnackbar}
severity={snackbar?.severity}
sx={{ width: "100%" }}
>
{snackbar.message}
</Alert>
</Snackbar>
</>
);
};
export default EntityActions;

View File

@@ -0,0 +1,49 @@
import { useState, useEffect } from "react";
import axios from "axios";
import { projectConfig } from "@/config/config";
const useAxios = (
url: string,
method = "GET",
payload = null,
isFullUrl = false,
shouldFetch = false,
) => {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
const fetch = () => {
setLoading(true);
setError(null);
const finalUrl = isFullUrl ? url : projectConfig.BASE_URL + url;
const axiosConfig = {
url: finalUrl,
method,
data: payload,
};
axios(axiosConfig)
.then((response) => {
setData(response.data);
})
.catch((error) => {
setError(error);
})
.finally(() => {
setLoading(false);
});
};
useEffect(() => {
if (shouldFetch) {
fetch();
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [url, method, JSON.stringify(payload), shouldFetch]);
return { data, loading, error, refetch: fetch };
};
export default useAxios;

View File

@@ -1,33 +0,0 @@
import { useState, useEffect } from "react";
import axios from "axios";
import { projectConfig } from "@/config/config";
const useFetch = (url: string) => {
const [data, setData] = useState([]);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
const fetch = () => {
setLoading(true);
axios
.get(projectConfig.BASE_URL + url)
.then((response) => {
setData(response.data);
})
.catch((error) => {
setError(error);
})
.finally(() => {
setLoading(false);
});
};
useEffect(() => {
fetch();
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [url]);
return { data, loading, error, fetch };
};
export default useFetch;

View File

@@ -1,7 +1,7 @@
import { getGroupColor, sanitizeDID } from "@/utils/helpers"; import { getGroupColor, sanitizeDID } from "@/utils/helpers";
export const generateMermaidString = (data: any) => { export const generateMermaidString = (data: any) => {
if (!data) return ""; if (!data || !data.length) return "";
let mermaidString = "sequenceDiagram\n"; let mermaidString = "sequenceDiagram\n";
const participantDetails = new Map(); const participantDetails = new Map();

View File

@@ -43,32 +43,48 @@ const SequenceDiagram = () => {
swrKey: eventMessagesKeyFunc, swrKey: eventMessagesKeyFunc,
} = useGetAllEventmessages(); } = useGetAllEventmessages();
const mermaidRef: any = useRef(null);
const [scale, setScale] = useState(1); const [scale, setScale] = useState(1);
const [openFilters, setOpenFilters] = useState(false); const [openFilters, setOpenFilters] = useState(false);
const [sequenceNr, setSequenceNr] = useState(""); const [sequenceNr, setSequenceNr] = useState("");
const hasData = eventMessagesData?.data;
const mermaidRef: any = useRef(null);
const hasData = eventMessagesData?.data && eventMessagesData?.data.length > 0;
const mermaidString = generateMermaidString(eventMessagesData?.data); const mermaidString = generateMermaidString(eventMessagesData?.data);
const allEventMessages = extractAllEventMessages(eventMessagesData?.data); const allEventMessages = extractAllEventMessages(eventMessagesData?.data);
const dataDependency = JSON.stringify(hasData ? eventMessagesData?.data : "");
useEffect(() => { useEffect(() => {
if (!loadingEventMessages && hasData) const currentMermaidRef = mermaidRef?.current;
mermaid.initialize({
startOnLoad: false,
securityLevel: "loose",
sequence: {
mirrorActors: true,
showSequenceNumbers: true,
},
});
if (mermaidRef.current) { if (!loadingEventMessages && hasData) {
mermaidRef.current.innerHTML = mermaidString; if (
mermaid.init(undefined, mermaidRef.current); currentMermaidRef &&
!currentMermaidRef.getAttribute("data-processed")
) {
mermaid.initialize({
startOnLoad: false,
securityLevel: "loose",
sequence: {
mirrorActors: true,
showSequenceNumbers: true,
},
});
}
if (currentMermaidRef) {
currentMermaidRef.innerHTML = mermaidString;
mermaid.init(undefined, currentMermaidRef);
}
} }
}, [loadingEventMessages, hasData, mermaidString]); return () => {
if (currentMermaidRef) {
currentMermaidRef.removeAttribute("data-processed");
currentMermaidRef.innerHTML = "";
}
};
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [dataDependency]);
useEffect(() => { useEffect(() => {
if (mermaidRef.current) { if (mermaidRef.current) {

View File

@@ -93,7 +93,7 @@ export function Sidebar(props: SidebarProps) {
const menuEntityEntries: MenuEntry[] = React.useMemo(() => { const menuEntityEntries: MenuEntry[] = React.useMemo(() => {
if (entityData) { if (entityData) {
return Array.isArray(entityData.data) return Array.isArray(entityData.data)
? entityData.data.map((entity) => ({ ? entityData.data.map((entity: any) => ({
icon: <PersonIcon />, icon: <PersonIcon />,
label: entity.name, label: entity.name,
to: entity.name, to: entity.name,

View File

@@ -23,7 +23,8 @@ const CustomTable = ({ configuration, data, loading, tkey }: ICustomTable) => {
const renderTableCell = ( const renderTableCell = (
value: any, value: any,
cellKey: string, cellKey: string,
render?: (param: any) => void | undefined, render?: (param: any, data?: any) => void | undefined,
rowData?: any,
) => { ) => {
let renderedValue = value; let renderedValue = value;
@@ -35,7 +36,7 @@ const CustomTable = ({ configuration, data, loading, tkey }: ICustomTable) => {
renderedValue = <Checkbox disabled checked={value} />; renderedValue = <Checkbox disabled checked={value} />;
// cover use case if we want to render a component // cover use case if we want to render a component
if (render) renderedValue = render(value); if (render) renderedValue = render(value, rowData);
// catch use case where the value is an object but the render function is not provided in the table config // catch use case where the value is an object but the render function is not provided in the table config
if ( if (
@@ -66,17 +67,18 @@ const CustomTable = ({ configuration, data, loading, tkey }: ICustomTable) => {
</TableRow> </TableRow>
</TableHead> </TableHead>
<TableBody> <TableBody>
{data.map((data: any, rowIndex: number) => ( {data.map((rowData: any, rowIndex: number) => (
<StyledTableRow key={rowIndex}> <StyledTableRow key={rowIndex}>
{configuration.map( {configuration.map(
(column: CustomTableConfiguration, columnIndex: number) => { (column: CustomTableConfiguration, columnIndex: number) => {
const cellValue: any = data[column.key]; const cellValue: any = rowData[column.key];
const cellKey = tkey + ":" + column.key + ":" + rowIndex; const cellKey = tkey + ":" + column.key + ":" + rowIndex;
const renderComponent = column?.render; const renderComponent = column?.render;
return renderTableCell( return renderTableCell(
cellValue, cellValue,
cellKey + ":" + columnIndex, cellKey + ":" + columnIndex,
renderComponent, renderComponent,
rowData,
); );
}, },
)} )}

View File

@@ -1,20 +1,3 @@
// AP - Summary
export const APSummaryDetails = [
{
label: "DID",
value: "did:sov:test:1274",
},
{
label: "IP",
value: "127.0.0.2",
},
{
label: "Network",
value: "Carlo's Home Network",
},
];
// AP - 2 Tables Configurations to display labels // AP - 2 Tables Configurations to display labels
export const APAttachmentsTableConfig = [ export const APAttachmentsTableConfig = [

View File

@@ -1,7 +1,5 @@
import { Button, IconButton, Tooltip } from "@mui/material"; import { Button } from "@mui/material";
import AddCircleIcon from "@mui/icons-material/AddCircle"; import EntityActions from "@/components/entity_actions";
import RemoveCircleIcon from "@mui/icons-material/RemoveCircle";
import DeleteIcon from "@mui/icons-material/Delete";
export const ClientTableConfig = [ export const ClientTableConfig = [
{ {
@@ -88,39 +86,10 @@ export const ServiceTableConfig = [
{ {
key: "action", key: "action",
label: "Actions", label: "Actions",
render: () => { render: (value: any, rowData?: any) => {
return ( if (value && value?.data.length > 0)
<> return <EntityActions rowData={rowData} endpointData={value.data} />;
<Tooltip title="Register" placement="top"> else return "N/A";
<IconButton disabled size="small">
<AddCircleIcon />
</IconButton>
</Tooltip>
<Tooltip title="De-register" placement="top">
<IconButton disabled size="small">
<RemoveCircleIcon />
</IconButton>
</Tooltip>
<Tooltip title="Delete" placement="top">
<IconButton disabled size="small" color="secondary">
<DeleteIcon />
</IconButton>
</Tooltip>
</>
);
// let renderedValue: any = "";
// if (typeof value === "object")
// renderedValue = (
// <>
// {[...value.data, { name: 'Delete', endpoint: '' }].map((actionType: any) => (
// <>
// <Button disabled style={{ marginRight: 8 }} variant="outlined" size="small">{actionType.name}</Button>
// </>
// ))}
// </>
// );
// return renderedValue;
}, },
}, },
]; ];

View File

@@ -9,6 +9,7 @@ import BuildIcon from "@mui/icons-material/Build";
export const projectConfig: any = { export const projectConfig: any = {
BASE_URL: "http://localhost:2979/api/v1", BASE_URL: "http://localhost:2979/api/v1",
REFRESH_FREQUENCY: 5000,
GROUPS: [ GROUPS: [
{ {
groupName: "Attachement", groupName: "Attachement",

View File

@@ -1,18 +1,5 @@
// DLG Summary Details
import { formatDateTime } from "@/utils/helpers"; import { formatDateTime } from "@/utils/helpers";
export const DLGSummaryDetails = [
{
label: "DID",
value: "did:sov:test:1274",
},
{
label: "URL",
value: "dlg.tu-berlin.de",
},
];
// DLG - 2 Tables Configurations to display labels // DLG - 2 Tables Configurations to display labels
export const DLGResolutionDummyData = [ export const DLGResolutionDummyData = [

View File

@@ -13,17 +13,22 @@ export interface ICustomTable {
export interface EntityDetails { export interface EntityDetails {
label: string; label: string;
value: string; value: string | undefined;
} }
export interface Entity { export interface Entity {
name: string; name?: string;
details: EntityDetails[]; details: EntityDetails[];
} }
export interface ISummaryDetails { export interface ISummaryDetails {
entity: any; entity: Entity;
fake?: boolean; fake?: boolean;
hasRefreshButton?: boolean; hasRefreshButton?: boolean;
onRefresh?: () => void; onRefresh?: () => void;
} }
export interface IEntityActions {
name: string;
endpoint: string;
}