A lot of Diagram Fixes as well as other code changes #70

Merged
Ghost merged 9 commits from diagram-fixes into main 2024-01-25 01:01:11 +00:00
19 changed files with 671 additions and 239 deletions

View File

@@ -139,7 +139,7 @@ export default function Client({ params }: { params: { name: string } }) {
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
const cardContentRef = useRef(null);
const cardContentRef = useRef<HTMLDivElement>(null);
const [snackbarOpen, setSnackbarOpen] = useState(false);
const [snackbarMessage, setSnackbarMessage] = useState<
SnackMessage | undefined

View File

@@ -42,7 +42,6 @@ export default function Home() {
entity={{ name: "Home", details: [] }}
hasRefreshButton={true}
onRefresh={onRefresh}
hasAttachDetach={false}
/>
<div>

View File

@@ -51,7 +51,6 @@ export default function RootLayout({
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="description" content="Service Aware Networks" />
<link rel="icon" href="tub-favicon.ico" sizes="any" />
{/* <script src="https://cdn.jsdelivr.net/npm/mermaid/dist/mermaid.min.js"></script> */}
<script
// eslint-disable-next-line react/no-danger
dangerouslySetInnerHTML={{

View File

@@ -1,26 +1,50 @@
import { useState } from "react";
import { Button, Snackbar } from "@mui/material";
import { useState, RefObject } from "react";
import { Tooltip, Snackbar } from "@mui/material";
import ContentCopyIcon from "@mui/icons-material/ContentCopy";
const CopyToClipboard = ({ contentRef }: { contentRef: any }) => {
const CopyToClipboard = ({
contentRef,
textToCopy,
}: {
contentRef?: RefObject<HTMLDivElement>;
textToCopy?: string;
}) => {
const [open, setOpen] = useState(false);
const handleClick = () => {
if (contentRef.current) {
const text = contentRef.current.textContent;
navigator.clipboard.writeText(text);
// Prioritize direct text copy if 'textToCopy' is provided
const text = textToCopy || contentRef?.current?.textContent || "";
const copiedText = textToCopy ? JSON.stringify(text, null, 2) : text;
if (text) {
navigator.clipboard.writeText(copiedText).then(
() => {
setOpen(true);
},
(err) => {
console.error("Could not copy text: ", err);
},
);
}
};
return (
<>
<Button onClick={handleClick}>Copy</Button>
<Tooltip placement="left" title="Copy to Clipboard">
<ContentCopyIcon onClick={handleClick} className="cursor-pointer" />
</Tooltip>
<Snackbar
open={open}
onClose={() => setOpen(false)}
autoHideDuration={2000}
message="Copied to clipboard"
message="Copied to clipboard!"
anchorOrigin={{
vertical: "bottom",
horizontal: "left",
}}
/>
</>
);
};
export default CopyToClipboard;

View File

@@ -0,0 +1,73 @@
# CopyToClipboard Component
## Overview
The `CopyToClipboard` component is a versatile UI component designed to facilitate copying text to the user's clipboard. It can copy text from two sources: directly from a passed text string prop (`textToCopy`) or from the text content of a referenced div element (`contentRef`). The component includes a clickable icon and displays a confirmation snackbar notification once the copy action is successful.
## Props
The component accepts the following props:
1. `textToCopy` (optional): A string representing the direct text you want to copy. If provided, this text is copied to the clipboard when the icon is clicked.
2. `contentRef` (optional): A `RefObject<HTMLDivElement>` that references a div element. The text content of this div is copied to the clipboard if `textToCopy` is not provided.
## Behavior
- Copy Action: When the copy icon is clicked, the component:
- Prioritizes copying the text from the `textToCopy` prop if it's provided and not an empty string.
- If `textToCopy` is not provided or is empty, it then attempts to copy the text content of the element referenced by contentRef.
- Uses the Clipboard API (`navigator.clipboard.writeText`) to copy the text to the user's clipboard.
- Displays a snackbar notification confirming the copy action if successful.
- Snackbar Notification: A temporary notification that:
- Appears after the text is successfully copied.
- Displays the message "Copied to clipboard!".
- Disappears automatically after 2000 milliseconds and is positioned at the bottom left of the screen.
## How to Use
1. Import the `CopyToClipboard` component.
2. Use the component in one of the following ways:
3. Pass a `textToCopy` prop with the text you want to copy, OR
4. Pass a `contentRef` prop pointing to a div element containing the text you want to copy.
5. Render the `CopyToClipboard` component where you want the copy icon to appear.
## Example
Using `textToCopy` prop:
```javascript
import CopyToClipboard from "./CopyToClipboard";
const SomeComponent = () => {
return (
<div>
<CopyToClipboard textToCopy="Text to be copied" />
</div>
);
};
export default SomeComponent;
```
Using `contentRef` prop:
```javascript
import React, { useRef } from "react";
import CopyToClipboard from "./CopyToClipboard";
const SomeComponent = () => {
const textRef = useRef(null);
return (
<div>
<div ref={textRef}>Text to copy from ref</div>
<CopyToClipboard contentRef={textRef} />
</div>
);
};
export default SomeComponent;
```

View File

@@ -1,6 +1,6 @@
import { useState, useEffect } from "react";
import axios from "axios";
import { BASE_URL } from "@/constants";
import { projectConfig } from "@/config/config";
const useFetch = (url: string) => {
const [data, setData] = useState([]);
@@ -10,7 +10,7 @@ const useFetch = (url: string) => {
const fetch = () => {
setLoading(true);
axios
.get(BASE_URL + url)
.get(projectConfig.BASE_URL + url)
.then((response) => {
setData(response.data);
})

View File

@@ -1,136 +1,93 @@
import { Eventmessage } from "@/api/model";
import { getGroupColor, sanitizeDID } from "@/utils/helpers";
export const generateMermaidString = (data: Eventmessage[] | undefined) => {
if (!data || data.length === 0) return "";
const participants = Array.from(
new Set(data.flatMap((item) => [item.src_did, item.des_did])),
);
export const generateMermaidString = (data: any) => {
if (!data) return "";
let mermaidString = "sequenceDiagram\n";
const participantDetails = new Map();
participants.forEach((participant, index) => {
mermaidString += ` participant ${String.fromCharCode(
65 + index,
)} as ${participant}\n`;
// Collect all unique participants along with their sanitized DIDs
data.forEach((item: any) => {
Object.values(item.groups).forEach((group: any) => {
group.forEach((msg: any) => {
// Apply sanitization to src_name and des_name if they are in DID format
const sanitizedSrcName = msg.src_name.includes(":")
? sanitizeDID(msg.src_name)
: msg.src_name;
const sanitizedDesName = msg.des_name.includes(":")
? sanitizeDID(msg.des_name)
: msg.des_name;
participantDetails.set(sanitizedSrcName, sanitizeDID(msg.src_did));
participantDetails.set(sanitizedDesName, sanitizeDID(msg.des_did));
});
});
});
let currentGroupId: number | null = null;
data.forEach((item, index) => {
const srcParticipant = String.fromCharCode(
65 + participants.indexOf(item.src_did),
);
const desParticipant = String.fromCharCode(
65 + participants.indexOf(item.des_did),
);
const timestamp = new Date(item.timestamp * 1000).toLocaleString();
const message = item.msg.text || `Event message ${index + 1}`;
if (item.group_id !== currentGroupId) {
if (currentGroupId !== null) {
mermaidString += ` end\n`;
}
mermaidString += ` alt Group ${item.group_id}\n`;
currentGroupId = item.group_id;
}
mermaidString += ` ${srcParticipant}->>${desParticipant}: [${timestamp}] ${message}\n`;
// Add participants to the mermaid string with names and sanitized DIDs
participantDetails.forEach((sanitizedDID, name) => {
mermaidString += ` participant ${name} as ${name} <br/>${sanitizedDID}\n`;
});
if (currentGroupId !== null) {
mermaidString += ` end\n`;
}
// Iterate through each group
data.forEach((item: any) => {
let groupParticipants: any = new Set(); // This will collect participants for the current group
// Collect participants involved in each specific group
Object.values(item.groups).forEach((group: any) => {
group.forEach((msg: any) => {
const sanitizedSrcName = msg.src_name.includes(":")
? sanitizeDID(msg.src_name)
: msg.src_name;
const sanitizedDesName = msg.des_name.includes(":")
? sanitizeDID(msg.des_name)
: msg.des_name;
groupParticipants.add(sanitizedSrcName);
groupParticipants.add(sanitizedDesName);
});
});
// Convert the set of participants to a sorted array and then to a string
groupParticipants = Array.from(groupParticipants).sort().join(",");
// Get the group color from the config
const groupColor = getGroupColor(item.group_name);
// Add group note with only involved participants
mermaidString += `\n rect ${groupColor}\n Note over ${groupParticipants}: ${item.group_name}\n`;
Object.entries(item.groups).forEach(([groupId, messages]: any) => {
mermaidString += ` alt Group Id ${groupId}\n`;
messages.forEach((msg: any) => {
const sanitizedSrcName = msg.src_name.includes(":")
? sanitizeDID(msg.src_name)
: msg.src_name;
const sanitizedDesName = msg.des_name.includes(":")
? sanitizeDID(msg.des_name)
: msg.des_name;
const arrow = sanitizedSrcName > sanitizedDesName ? "-->>" : "->>";
mermaidString += ` ${sanitizedSrcName}${arrow}${sanitizedDesName}: [${msg.msg_type_name}]: Event Message ${msg.id}\n`;
});
mermaidString += " end\n";
});
mermaidString += " end\n";
});
return mermaidString;
};
// Dummy Data
export function extractAllEventMessages(data: any) {
const allMessagesArray: any = [];
export const dataFromBE = [
{
id: 12,
timestamp: 1704892813,
group: 0,
group_id: 12,
// "group_name": "Data",
msg_type: 4,
src_did: "did:sov:test:121",
// "src_name": "Entity A",
des_did: "did:sov:test:120",
// "des_name": "Entity B",
msg: {
text: "Hello World",
},
},
{
id: 60,
timestamp: 1704892823,
group: 1,
group_id: 19,
msg_type: 4,
src_did: "did:sov:test:122",
des_did: "did:sov:test:121",
msg: {},
},
{
id: 30162,
timestamp: 1704892817,
group: 1,
group_id: 53,
msg_type: 2,
src_did: "did:sov:test:121",
des_did: "did:sov:test:122",
msg: {},
},
{
id: 63043,
timestamp: 1704892809,
group: 0,
group_id: 12,
msg_type: 3,
src_did: "did:sov:test:121",
des_did: "did:sov:test:120",
msg: {},
},
{
id: 66251,
timestamp: 1704892805,
group: 0,
group_id: 51,
msg_type: 1,
src_did: "did:sov:test:120",
des_did: "did:sov:test:121",
msg: {},
},
{
id: 85434,
timestamp: 1704892807,
group: 0,
group_id: 51,
msg_type: 2,
src_did: "did:sov:test:120",
des_did: "did:sov:test:121",
msg: {},
},
{
id: 124842,
timestamp: 1704892819,
group: 1,
group_id: 19,
msg_type: 3,
src_did: "did:sov:test:122",
des_did: "did:sov:test:121",
msg: {},
},
{
id: 246326,
timestamp: 1704892815,
group: 1,
group_id: 53,
msg_type: 1,
src_did: "did:sov:test:121",
des_did: "did:sov:test:122",
msg: {},
},
];
if (!data || data.length === 0) return allMessagesArray;
else
data.forEach((groupData: any) => {
Object.values(groupData.groups).forEach((messages: any) => {
messages.forEach((message: any) => {
allMessagesArray.push(message);
});
});
});
return allMessagesArray;
}

View File

@@ -2,32 +2,56 @@
import { useRef, useEffect, useState } from "react";
import mermaid from "mermaid";
import { IconButton } from "@mui/material";
import {
Button,
Card,
Chip,
Dialog,
DialogActions,
Tooltip,
DialogContent,
DialogContentText,
DialogTitle,
IconButton,
List,
TextField,
} from "@mui/material";
//Icons
import RefreshIcon from "@mui/icons-material/Refresh";
import ZoomInIcon from "@mui/icons-material/ZoomIn";
import ZoomOutIcon from "@mui/icons-material/ZoomOut";
import FullscreenIcon from "@mui/icons-material/Fullscreen";
import DownloadIcon from "@mui/icons-material/Download";
import ResetIcon from "@mui/icons-material/Autorenew";
import Tooltip from "@mui/material/Tooltip";
import FilterAltIcon from "@mui/icons-material/FilterAlt";
// Custom Components
import { NoDataOverlay } from "../noDataOverlay";
import { LoadingOverlay } from "../join/loadingOverlay";
import { useGetAllEventmessages } from "@/api/eventmessages/eventmessages";
import { mutate } from "swr";
import { LoadingOverlay } from "../join/loadingOverlay";
//import { generateMermaidString } from "./helpers";
import { extractAllEventMessages, generateMermaidString } from "./helpers";
import CopyToClipboard from "../copy_to_clipboard";
import { formatDateTime, getGroupById } from "@/utils/helpers";
const SequenceDiagram = () => {
const {
// data: eventMessagesData,
data: eventMessagesData,
isLoading: loadingEventMessages,
swrKey: eventMessagesKeyFunc,
} = useGetAllEventmessages();
const mermaidRef: any = useRef(null);
const [scale, setScale] = useState(1);
const hasData = false; // TODO: Readd this, right now it's always false
const [openFilters, setOpenFilters] = useState(false);
const mermaidString = ""; //generateMermaidString(eventMessagesData?.data);
const [sequenceNr, setSequenceNr] = useState("");
const hasData = eventMessagesData?.data;
const mermaidString = generateMermaidString(eventMessagesData?.data);
const allEventMessages = extractAllEventMessages(eventMessagesData?.data);
useEffect(() => {
if (!loadingEventMessages && hasData)
@@ -35,7 +59,8 @@ const SequenceDiagram = () => {
startOnLoad: false,
securityLevel: "loose",
sequence: {
mirrorActors: false,
mirrorActors: true,
showSequenceNumbers: true,
},
});
@@ -126,16 +151,37 @@ const SequenceDiagram = () => {
}
};
const toggleFilters = () => {
setOpenFilters((prevState) => !prevState);
};
const onSearchBySeqNumber = (e: any) => {
setSequenceNr(e.target.value);
};
const isFilterMatch = (index: number) => {
if (!sequenceNr) return true;
const filterSeqNrInt = parseInt(sequenceNr, 10);
return index + 1 === filterSeqNrInt;
};
if (loadingEventMessages)
return <LoadingOverlay title="Loading Diagram" subtitle="Please wait..." />;
return (
<>
<div className="flex flex-col items-end">
{hasData ? (
<>
<div className="flex justify-end">
<Tooltip placement="top" title="Filter Messages">
<IconButton color="primary" onClick={toggleFilters}>
<FilterAltIcon />
</IconButton>
</Tooltip>
<Tooltip placement="top" title="Refresh Diagram">
<IconButton color="default" onClick={onRefresh}>
<IconButton color="primary" onClick={onRefresh}>
<RefreshIcon />
</IconButton>
</Tooltip>
@@ -175,6 +221,117 @@ const SequenceDiagram = () => {
</div>
)}
</div>
{openFilters && (
<>
<Dialog
open={openFilters}
keepMounted
fullWidth
maxWidth="lg"
onClose={toggleFilters}
>
<DialogTitle>All Event Messages</DialogTitle>
<DialogContent>
<DialogContentText>
<div className="flex items-center gap-2.5">
<label>Search by Sequence # </label>
<TextField
onChange={onSearchBySeqNumber}
size="small"
variant="outlined"
/>
</div>
<List className="w-full" component="nav">
{allEventMessages
.filter((_: any, index: number) => {
return isFilterMatch(index);
})
.map((message: any, index: number) => {
const {
msg_type_name: msgType,
des_name,
src_name,
group,
group_id,
timestamp,
src_did,
des_did,
// msg, TODO: Need to use the content inside the msg to display in the diagram
} = message;
const formattedTimeStamp = formatDateTime(timestamp);
const { groupIcon: IconComponent, groupName } =
getGroupById(group);
return (
<div
key={index}
style={{ marginBottom: 12 }}
className="flex items-center gap-5"
>
<Chip label={sequenceNr ? sequenceNr : ++index} />
<Card style={{ padding: 10 }} className="w-full">
<div
style={{ marginBottom: 12 }}
className="flex justify-between"
>
<div>
<span
style={{
marginBottom: 12,
fontWeight: "bold",
}}
className="flex items-center gap-2"
>
{IconComponent} {groupName}{" "}
<Chip label={msgType} />
</span>
<span>
Sender: {src_name} <Chip label={src_did} /> |{" "}
</span>
<span>
Receiver: {des_name} <Chip label={des_did} />{" "}
|{" "}
</span>
<span>Group: {group} | </span>
<span>Group ID: {group_id}</span>
</div>
<span>{formattedTimeStamp}</span>
</div>
<span className="font-bold">
Event Message {sequenceNr ? sequenceNr : index++}
</span>
<div
className="mt-4 flex"
style={{
border: "1px solid #f1f1f1",
borderRadius: 5,
}}
>
<pre className="flex-1 p-2">
{JSON.stringify(message, null, 2)}
</pre>
<div className="shrink-0 p-2">
<CopyToClipboard textToCopy={message} />
</div>
</div>
</Card>
</div>
);
})}
</List>
</DialogContentText>
</DialogContent>
<DialogActions className="p-4">
<Button variant="contained" onClick={toggleFilters}>
Close
</Button>
</DialogActions>
</Dialog>
</>
)}
</>
);
};

View File

@@ -13,29 +13,17 @@ import { EntityDetails, ISummaryDetails } from "@/types";
const SummaryDetails = ({
entity,
hasRefreshButton,
hasAttachDetach,
fake,
onRefresh,
}: ISummaryDetails) => {
const cardContentRef = useRef(null);
const cardContentRef = useRef<HTMLDivElement>(null);
const hasDetails = entity.details && entity.details.length > 0;
return (
<>
<div
style={{
display: "flex",
alignItems: "center",
justifyContent: "space-between",
}}
>
<div className="flex items-center justify-between">
<h2>{entity.name}</h2>
<div>
{hasAttachDetach && (
<Button className="mr-6" variant="contained">
Attach / Detach
</Button>
)}
{hasRefreshButton && (
<Button onClick={onRefresh} variant="contained">
Refresh
@@ -46,7 +34,7 @@ const SummaryDetails = ({
{hasDetails && (
<Card variant="outlined">
<CardHeader
subheader={fake ? "Summary (Fake Data)" : "Summary"}
subheader={`Summary ${fake ? "(Fake Data)" : ""}`}
action={<CopyToClipboard contentRef={cardContentRef} />}
/>
<CardContent ref={cardContentRef}>

View File

@@ -0,0 +1,52 @@
# SummaryDetails Component
## Overview
The `SummaryDetails` component is a flexible UI component designed to display a summary of details related to a specific entity in a card format. It is equipped with optional functionalities such as refreshing the data.
## Props
The component accepts the following props:
1. `entity`: An object representing the entity whose details are to be displayed. It should have a name and details, where details is an array of `EntityDetails` objects.
2. `hasRefreshButton` (optional): A boolean indicating if a Refresh button should be displayed. If true, the button is shown, allowing the user to refresh the entity details.
3. `fake` (optional): A boolean indicating if the displayed data is fake. If true, a label '(Fake Data)' is displayed in the card's header.
4. `onRefresh` (optional): A function to be called when the Refresh button is clicked. It should handle the logic for refreshing the entity details.
## UI Structure
- The component starts with a flex container displaying the entity's name and optional button (Refresh) based on the props.
- If the entity has details (checked by `hasDetails`), it displays a card containing:
- A `CardHeader` with a subheader indicating it's a summary and whether the data is fake.
- A `CopyToClipboard` component attached to the card's action, allowing the user to copy the details.
- A `CardContent` section listing all the details. Each detail is displayed as a `Typography` component, showing the label and value of each `EntityDetails` item.
## How to Use
1. Import the `SummaryDetails` component.
2. Create an entity object with a name and details, where details is an array of objects with label and value.
3. Optionally, decide if you want the Refresh functionality by setting `hasRefreshButton` to `true`.
4. If using the `Refresh` functionality, provide an `onRefresh` function to handle the logic.
5. Render the `SummaryDetails` component with the desired props.
## Example
```javascript
<SummaryDetails
entity={{
name: "Sample Entity",
details: [
{ label: "Detail 1", value: "Value 1" },
{ label: "Detail 2", value: "Value 2" },
// ... more details
],
}}
hasRefreshButton={true}
onRefresh={() => {
// handle refresh button logic/callback
}}
/>
```

View File

@@ -36,9 +36,16 @@ const CustomTable = ({ configuration, data, loading, tkey }: ICustomTable) => {
// cover use case if we want to render a component
if (render) renderedValue = render(value);
if (typeof renderedValue === "object" && render === undefined) {
// catch use case where the value is an object but the render function is not provided in the table config
if (
typeof value === "object" &&
!Array.isArray(value) &&
render === undefined
) {
console.warn("Missing render function for column " + cellKey);
}
return (
<ErrorBoundary>
<StyledTableCell key={cellKey} align="left">

View File

@@ -0,0 +1,75 @@
# CustomTable Component
## Overview
The `CustomTable` component is a dynamic and flexible table designed to display data in a structured tabular format. It is highly customizable, allowing specific rendering for different data types and providing a user-friendly display for loading and empty data states.
## Props
The component accepts the following props:
1. `configuration`: An array of `CustomTableConfiguration` objects defining the structure and customization options for table columns, including:
- `key`: Corresponds to the key in the data objects for the column.
- `label`: Text label for the column header.
- `render` (optional): A function for custom rendering of the cell's content.
- `data`: An array of data objects, each representing a row in the table.
- `loading` (optional): If `true`, displays a loading state (skeleton screen).
- `tkey`: A unique key for the table, used for constructing unique cell keys.
## Behavior
- **Loading State**: Displays a `Skeleton` loader when `loading` is `true`.
- **Empty Data State**: Displays a `NoDataOverlay` component with a message if no data is available.
- **Data Rendering**:
- Dynamically renders cells based on `configuration`.
- Handles different data types:
- Joins array elements with a comma.
- Shows a disabled checkbox for boolean values.
- Uses the provided `render` function for custom rendering.
- Logs a warning if a cell's value is an object (not an array), and no `render` function is provided.
- **Error Handling**: Each cell is wrapped in an `ErrorBoundary` component for graceful error handling.
## How to Use
1. Import the `CustomTable` component.
2. Define the `configuration` for table columns.
3. Provide `data` as an array of objects corresponding to the configuration.
4. Optionally, control the loading state with the `loading` prop.
5. Provide a unique `tkey` for the table.
## Example
```javascript
import CustomTable from "./CustomTable";
const tableConfig = [
{ key: "name", label: "Name" },
{ key: "age", label: "Age" },
{
key: "isActive",
label: "Active",
render: (isActive) => (isActive ? "Yes" : "No"),
},
];
const tableData = [
{ name: "John Doe", age: 30, isActive: true },
{ name: "Jane Smith", age: 25, isActive: false },
];
const SomeComponent = () => {
return (
<div>
<CustomTable
configuration={tableConfig}
data={tableData}
loading={false}
tkey="unique-table-key"
/>
</div>
);
};
export default SomeComponent;
```

View File

@@ -4,7 +4,6 @@ import TableRow from "@mui/material/TableRow";
export const StyledTableCell = styled(TableCell)(({ theme }) => ({
[`&.${tableCellClasses.head}`]: {
// backgroundColor: theme.palette.common.black,
backgroundColor: "#003258",
color: theme.palette.common.white,
},

View File

@@ -15,6 +15,8 @@ export const APSummaryDetails = [
},
];
// AP - 2 Tables Configurations to display labels
export const APAttachmentsTableConfig = [
{
key: "name",
@@ -61,29 +63,9 @@ export const APServiceRepositoryTableConfig = [
label: "Status",
render: (value: any) => {
let renderedValue: any = "";
if (Array.isArray(value.data)) {
renderedValue = value.data.join(", ");
} else {
console.error("Status is not an array", value);
}
if (Array.isArray(value.data)) renderedValue = value.data.join(", ");
else console.error("Status is not an array", value);
return renderedValue;
},
},
// {
// key: "other",
// label: "Type",
// render: (value: any) => {
// let renderedValue: any = "";
// if (typeof value === "object") {
// const label = Object.keys(value)[0];
// const info = value[label];
// renderedValue = (
// <code>
// {label} {info}
// </code>
// );
// }
// return renderedValue;
// },
// },
];

View File

@@ -0,0 +1,111 @@
import AttachmentIcon from "@mui/icons-material/Attachment";
import ArticleIcon from "@mui/icons-material/Article";
import ConstructionIcon from "@mui/icons-material/Construction";
import AssignmentTurnedInIcon from "@mui/icons-material/AssignmentTurnedIn";
import RemoveCircleIcon from "@mui/icons-material/RemoveCircle";
import AddCircleIcon from "@mui/icons-material/AddCircle";
import PageviewIcon from "@mui/icons-material/Pageview";
import BuildIcon from "@mui/icons-material/Build";
export const projectConfig: any = {
BASE_URL: "http://localhost:2979/api/v1",
GROUPS: [
{
groupName: "Attachement",
groupId: 1,
groupColor: "rgb(230, 230, 250)",
groupIcon: <AttachmentIcon />,
messageTypes: [
{ id: 1, label: "Attachment Request Send" },
{ id: 2, label: "Attachment Request Received" },
{ id: 3, label: "Attachment Response Send" },
{ id: 4, label: "Attachment Response Received" },
],
},
{
groupName: "Connection Setup",
groupId: 2,
groupColor: "rgb(245, 222, 179)",
groupIcon: <ConstructionIcon />,
messageTypes: [
{ id: 1, label: "Connection request send" },
{ id: 2, label: "Connection request received" },
{ id: 3, label: "Connection response send" },
{ id: 4, label: "Connection response received" },
],
},
{
groupName: "Presentation",
groupId: 3,
groupColor: "rgb(255, 209, 220)",
groupIcon: <ArticleIcon />,
messageTypes: [
{ id: 1, label: "Request send" },
{ id: 2, label: "Request received" },
{ id: 3, label: "Presentation send" },
{ id: 4, label: "Presentation received" },
{ id: 5, label: "Presentation acknowledged" },
],
},
{
groupName: "DID Resolution",
groupId: 4,
groupColor: "rgb(189, 255, 243)",
groupIcon: <AssignmentTurnedInIcon />,
messageTypes: [
{ id: 1, label: "DID Resolution Request send" },
{ id: 2, label: "DID Resolution Request received" },
{ id: 3, label: "DID Resolution Response send" },
{ id: 4, label: "DID Resolution Response received" },
],
},
{
groupName: "Service De-registration",
groupId: 5,
groupColor: "rgb(255, 218, 185)",
groupIcon: <RemoveCircleIcon />,
messageTypes: [
{ id: 1, label: "Service De-registration send" },
{ id: 2, label: "Service De-registration received" },
{ id: 3, label: "Service De-registration successful send" },
{ id: 4, label: "Service De-registration successful received" },
],
},
{
groupName: "Service Registration",
groupId: 6,
groupColor: "rgb(200, 162, 200)",
groupIcon: <AddCircleIcon />,
messageTypes: [
{ id: 1, label: "Service Registration send" },
{ id: 2, label: "Service Registration received" },
{ id: 3, label: "Service Registration successful send" },
{ id: 4, label: "Service Registration successful received" },
],
},
{
groupName: "Service Discovery",
groupId: 7,
groupColor: "rgb(255, 250, 205)",
groupIcon: <PageviewIcon />,
messageTypes: [
{ id: 1, label: "Service Discovery send" },
{ id: 2, label: "Service Discovery received" },
{ id: 3, label: "Service Discovery Result send" },
{ id: 4, label: "Service Discovery Result received" },
],
},
{
groupName: "Service Operation",
groupId: 8,
groupColor: "rgb(135, 206, 235)",
groupIcon: <BuildIcon />,
messageTypes: [
{ id: 1, label: "Service Request Send" },
{ id: 2, label: "Service Request Received" },
{ id: 3, label: "Service Response Send" },
{ id: 4, label: "Service Response Received" },
],
},
],
};

View File

@@ -13,7 +13,7 @@ export const DLGSummaryDetails = [
},
];
// DLG Resolution Table
// DLG - 2 Tables Configurations to display labels
export const DLGResolutionDummyData = [
{

View File

@@ -1,9 +0,0 @@
const BASE_URL = "http://localhost:2979/api/v1";
// Home View
const HOME_VIEW_TABLE = "/get_entities";
// Access Point
const SERVICE_REPOSITORY_URL = "/get_repositories";
export { BASE_URL, HOME_VIEW_TABLE, SERVICE_REPOSITORY_URL };

View File

@@ -25,6 +25,5 @@ export interface ISummaryDetails {
entity: any;
fake?: boolean;
hasRefreshButton?: boolean;
hasAttachDetach?: boolean;
onRefresh?: () => void;
}

View File

@@ -1,5 +1,8 @@
export const formatDateTime = (date: string) => {
const _date = new Date(date);
import { projectConfig } from "@/config/config";
export const formatDateTime = (date: string | number) => {
const dateToFormat = typeof date === "number" ? date * 1000 : date;
const _date = new Date(dateToFormat);
return _date.toLocaleDateString("en-US", {
year: "numeric",
month: "long",
@@ -10,3 +13,19 @@ export const formatDateTime = (date: string) => {
hour12: true,
});
};
export function sanitizeDID(did: string) {
return did.replace(/:/g, "_");
}
export function getGroupColor(groupName: string) {
const group = projectConfig.GROUPS.find(
(g: any) => g.groupName === groupName,
);
return group ? group.groupColor : "rgb(211, 211, 211)"; // Light gray if not found
}
export function getGroupById(groupId: string | number) {
const group = projectConfig.GROUPS.find((g: any) => g.groupId === groupId);
return group ? group : {};
}