195 lines
6.9 KiB
TypeScript
195 lines
6.9 KiB
TypeScript
import { useEffect, useState } from "react";
|
|
import { useDispatch, useSelector } from "react-redux";
|
|
import { useStompClient } from 'react-stomp-hooks';
|
|
import { RootState } from "../store";
|
|
import { useWsSubscription } from "../ws/subscriptions";
|
|
import { EventsObjectListResponse } from "../../types";
|
|
import IconRefresh from '@mui/icons-material/Refresh'
|
|
import { Box, Button, Typography, useTheme } from "@mui/material";
|
|
import { Tree } from "react-d3-tree";
|
|
import { EventChain, EventGroup, EventGroups, set } from "../store/chained-events-slice";
|
|
import { toUnixTimestamp, UnixTimestamp } from "../features/UxTc";
|
|
import { TableCellCustomizer, TablePropetyConfig } from "../features/table/table";
|
|
import ExpandableTable, { ExpandableItem } from "../features/table/expandableTable";
|
|
import { CustomNodeElementProps } from 'react-d3-tree';
|
|
|
|
|
|
interface RawNodeDatum {
|
|
name: string;
|
|
attributes?: Record<string, string | number | boolean>;
|
|
children?: RawNodeDatum[];
|
|
fill?: string;
|
|
}
|
|
|
|
// Transformasjonsfunksjon for EventChain
|
|
const transformEventChain = (eventChain: EventChain): RawNodeDatum => ({
|
|
name: eventChain.eventName,
|
|
attributes: {
|
|
//eventId: eventChain.eventId,
|
|
created: toUnixTimestamp({ timestamp: eventChain.created }) ?? "",
|
|
success: eventChain.success,
|
|
skipped: eventChain.skipped,
|
|
failure: eventChain.failure,
|
|
childrens: eventChain.events.length
|
|
},
|
|
fill: "white",
|
|
children: eventChain.events.map(transformEventChain),
|
|
});
|
|
|
|
// Transformasjonsfunksjon for EventGroups
|
|
const transformEventGroups = (group: EventGroup): RawNodeDatum[] => {
|
|
return group.events.map(transformEventChain);
|
|
}
|
|
|
|
interface EventGroupToTreeView extends EventGroup {
|
|
underView: JSX.Element
|
|
}
|
|
|
|
export default function EventsChainPage() {
|
|
const muiTheme = useTheme();
|
|
const dispatch = useDispatch();
|
|
const client = useStompClient();
|
|
const cursor = useSelector((state: RootState) => state.chained)
|
|
const [useReferenceId, setUseReferenceId] = useState<string | null>(null);
|
|
const [treeData, setTreeData] = useState<RawNodeDatum[] | null>(null);
|
|
|
|
useWsSubscription<Array<EventGroup>>("/topic/chained/all", (response) => {
|
|
dispatch(set(response))
|
|
});
|
|
|
|
|
|
useEffect(() => {
|
|
if (Object.keys(cursor).length === 0) {
|
|
client?.publish({
|
|
destination: "/app/chained/all"
|
|
});
|
|
}
|
|
}, [cursor, client, dispatch]);
|
|
|
|
const onRefresh = () => {
|
|
client?.publish({
|
|
"destination": "/app/chained/all",
|
|
"body": "Potato"
|
|
})
|
|
}
|
|
|
|
useEffect(() => {
|
|
if (useReferenceId) {
|
|
const eventGroup = cursor.groups.find((group) => group.referenceId === useReferenceId);
|
|
if (eventGroup) {
|
|
const data = transformEventGroups(eventGroup);
|
|
console.log({
|
|
"info": "Tree data",
|
|
"data": data
|
|
})
|
|
setTreeData(data);
|
|
}
|
|
}
|
|
}, [useReferenceId, cursor])
|
|
|
|
const createTableCell: TableCellCustomizer<EventGroup> = (accessor, data) => {
|
|
switch (accessor) {
|
|
case "created": {
|
|
if (typeof data[accessor] === "number") {
|
|
const timestampObject = { timestamp: data[accessor] as number }; // Opprett et objekt med riktig struktur
|
|
return UnixTimestamp(timestampObject);
|
|
} else {
|
|
return null;
|
|
}
|
|
}
|
|
default: return null;
|
|
}
|
|
};
|
|
|
|
const columns: Array<TablePropetyConfig> = [
|
|
{ label: "ReferenceId", accessor: "referenceId" },
|
|
{ label: "File", accessor: "fileName" },
|
|
{ label: "Created", accessor: "created" },
|
|
];
|
|
|
|
|
|
function renderCustomNodeElement(nodeData: CustomNodeElementProps): JSX.Element {
|
|
const attr = nodeData.nodeDatum.attributes;
|
|
const nodeColor = attr?.success ? "green" : attr?.failure ? "red" : "yellow";
|
|
return (<>
|
|
<g>
|
|
<circle r="15" fill={nodeColor} onClick={nodeData.toggleNode} />
|
|
<text fill="white" stroke="white" strokeWidth="0" x="20">
|
|
{nodeData.nodeDatum.name}
|
|
</text>
|
|
{attr?.created && (
|
|
<text fill="lightgray" x="20" dy="20" strokeWidth="0">
|
|
Created: {attr?.created}
|
|
</text>
|
|
)}
|
|
{attr?.success && (
|
|
<text fill="lightgray" x="20" dy="40" strokeWidth="0">
|
|
Success
|
|
</text>
|
|
)}
|
|
{attr?.failure && (
|
|
<text fill="lightgray" x="20" dy="40" strokeWidth="0">
|
|
Failure
|
|
</text>
|
|
)}
|
|
{attr?.skipped && (
|
|
<text fill="lightgray" x="20" dy="40" strokeWidth="0">
|
|
Skipped
|
|
</text>
|
|
)}
|
|
{attr?.childrens && (
|
|
<text fill="lightgray" x="20" dy="60" strokeWidth="0">
|
|
{attr?.childrens} derived {Number(attr?.childrens) > 1 ? "events" : "event"}
|
|
</text>
|
|
)}
|
|
</g>
|
|
</>);
|
|
}
|
|
|
|
function renderExpandableItem(item: EventGroup): ExpandableItem<EventGroup> | null {
|
|
return {
|
|
tag: item.referenceId,
|
|
expandElement: (() => {
|
|
const data = transformEventGroups(item);
|
|
return (
|
|
<>
|
|
{(data) ? (
|
|
<div id="treeWrapper" style={{ width: '100%', height: '60vh', }}>
|
|
<Tree data={data} orientation="vertical" separation={{
|
|
nonSiblings: 3,
|
|
siblings: 2
|
|
}}
|
|
renderCustomNodeElement={renderCustomNodeElement}
|
|
/>
|
|
</div>
|
|
) : <Typography>Tree data not available</Typography>}
|
|
</>
|
|
);
|
|
})()
|
|
};
|
|
}
|
|
|
|
|
|
return (
|
|
<>
|
|
<Button
|
|
startIcon={<IconRefresh />}
|
|
onClick={onRefresh} sx={{
|
|
borderRadius: 5,
|
|
textTransform: 'none'
|
|
}}>Refresh
|
|
</Button>
|
|
<Box display="block">
|
|
<Box sx={{
|
|
display: "block",
|
|
height: "calc(100% - 120px)",
|
|
overflow: "hidden",
|
|
position: "absolute",
|
|
width: "100%"
|
|
}}>
|
|
<ExpandableTable items={cursor?.groups ?? []} columns={columns} cellCustomizer={createTableCell} expandableRender={renderExpandableItem} />
|
|
</Box>
|
|
</Box>
|
|
</>
|
|
)
|
|
} |