MediaProcessing/apps/ui/web/src/app/page/EventsChainPage.tsx

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>
</>
)
}