Skip to content

Commit

Permalink
[frontend] Interactive Timeline Display
Browse files Browse the repository at this point in the history
  • Loading branch information
Dimfacion committed Aug 28, 2024
1 parent 546ec3b commit 6197126
Show file tree
Hide file tree
Showing 3 changed files with 62 additions and 46 deletions.
96 changes: 53 additions & 43 deletions openbas-front/src/components/ChainedTimeline.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ import NodePhantom from './nodes/NodePhantom';

const useStyles = makeStyles(() => ({
container: {
marginTop: 60,
marginTop: 30,
paddingRight: 40,
},
rotatedIcon: {
Expand Down Expand Up @@ -73,6 +73,7 @@ const ChainedTimelineFlow: FunctionComponent<Props> = ({ injects, exerciseOrScen
const [currentUpdatedNode, setCurrentUpdatedNode] = useState<NodeInject | null>(null);
const [currentMousePosition, setCurrentMousePosition] = useState<XYPosition>({ x: 0, y: 0 });
const [newNodeCursorVisibility, setNewNodeCursorVisibility] = useState<'visible' | 'hidden'>('visible');
const [newNodeCursorClickable, setNewNodeCursorClickable] = useState<boolean>(true);
const [currentMouseTime, setCurrentMouseTime] = useState<string>('');

let timer: NodeJS.Timeout;
Expand Down Expand Up @@ -221,32 +222,42 @@ const ChainedTimelineFlow: FunctionComponent<Props> = ({ injects, exerciseOrScen
};

const onNodePhantomClick = (event: React.MouseEvent) => {
const position = reactFlow.screenToFlowPosition({ x: event.clientX, y: event.clientY });

const totalMinutes = moment.duration((position.x / gapSize) * minutesPerGapAllowed[minutesPerGapIndex] * 60, 's');
openCreateInjectDrawer({
inject_depends_duration_days: totalMinutes.days(),
inject_depends_duration_hours: totalMinutes.hours(),
inject_depends_duration_minutes: totalMinutes.minutes(),
});
if (newNodeCursorClickable) {
const position = reactFlow.screenToFlowPosition({ x: event.clientX, y: event.clientY });

const totalMinutes = moment.duration((position.x / gapSize) * minutesPerGapAllowed[minutesPerGapIndex] * 60, 's');
openCreateInjectDrawer({
inject_depends_duration_days: totalMinutes.days(),
inject_depends_duration_hours: totalMinutes.hours(),
inject_depends_duration_minutes: totalMinutes.minutes(),
});
}
};

const onMouseMove = (eventMove: React.MouseEvent) => {
clearTimeout(timer);
if (!draggingOnGoing) {
eventMove.persist();
const position = reactFlow.screenToFlowPosition({ x: eventMove.clientX, y: eventMove.clientY }, { snapToGrid: false });
const sidePosition = reactFlow.screenToFlowPosition({ x: eventMove.clientX - 25, y: eventMove.clientY }, { snapToGrid: false });

const viewPort = reactFlow.getViewport();
setCurrentMousePosition({ x: ((position.x * reactFlow.getZoom()) + viewPort.x - 25), y: ((position.y * reactFlow.getZoom()) + viewPort.y + 25) });
const momentOfTime = moment.utc(
moment.duration(convertCoordinatesToTime(
{ x: sidePosition.x, y: sidePosition.y },
), 's').asMilliseconds(),
);

setCurrentMouseTime(`${momentOfTime.dayOfYear() - 1} d, ${momentOfTime.hour()} h, ${momentOfTime.minute()} m`);
setCurrentMousePosition({ x: ((position.x * reactFlow.getZoom()) + viewPort.x - 25), y: ((position.y * reactFlow.getZoom()) + viewPort.y - 25) });

if (startDate === undefined) {
const momentOfTime = moment.utc(
moment.duration(convertCoordinatesToTime(
{ x: sidePosition.x, y: sidePosition.y },
), 's').asMilliseconds(),
);

setCurrentMouseTime(`${momentOfTime.dayOfYear() - 1} d, ${momentOfTime.hour()} h, ${momentOfTime.minute()} m`);
} else {
const momentOfTime = moment.utc(startDate)
.add(-new Date().getTimezoneOffset() / 60, 'h')
.add(convertCoordinatesToTime({ x: sidePosition.x, y: sidePosition.y }), 's');

setCurrentMouseTime(momentOfTime.format('MMMM Do, YYYY - h:mmA'));
}
}
};

Expand All @@ -256,10 +267,12 @@ const ChainedTimelineFlow: FunctionComponent<Props> = ({ injects, exerciseOrScen

const nodeMouseEnter = () => {
setNewNodeCursorVisibility('hidden');
setNewNodeCursorClickable(false);
};

const nodeMouseLeave = () => {
setNewNodeCursorVisibility('visible');
setNewNodeCursorClickable(true);
};

const updateMinutesPerGap = (incrementIndex: number) => {
Expand All @@ -275,17 +288,6 @@ const ChainedTimelineFlow: FunctionComponent<Props> = ({ injects, exerciseOrScen
<>
{injects.length > 0 ? (
<div className={classes.container} style={{ width: '100%', height: 350 }}>
<div className={classes.newBox}
style={{
top: currentMousePosition.y,
left: currentMousePosition.x,
visibility: newNodeCursorVisibility,
}}
>
<NodePhantom
time={currentMouseTime}
/>
</div>
<ReactFlow
nodes={nodes}
edges={edges}
Expand All @@ -309,7 +311,19 @@ const ChainedTimelineFlow: FunctionComponent<Props> = ({ injects, exerciseOrScen
nodeExtent={[[0, 0], [Infinity, Infinity]]}
defaultViewport={{ x: 60, y: 50, zoom: 0.75 }}
minZoom={0.3}
onClick={onNodePhantomClick}
>
<div className={classes.newBox}
style={{
top: currentMousePosition.y,
left: currentMousePosition.x,
visibility: newNodeCursorVisibility,
}}
>
<NodePhantom
time={currentMouseTime}
/>
</div>
<div
onMouseEnter={nodeMouseEnter}
onMouseLeave={nodeMouseLeave}
Expand All @@ -335,20 +349,16 @@ const ChainedTimelineFlow: FunctionComponent<Props> = ({ injects, exerciseOrScen
</ControlButton>
</Controls>
</div>
<div
onClick={onNodePhantomClick}
>
<CustomTimelineBackground
gap={gapSize}
minutesPerGap={minutesPerGapAllowed[minutesPerGapIndex]}
/>
<CustomTimelinePanel
gap={gapSize}
minutesPerGap={minutesPerGapAllowed[minutesPerGapIndex]}
viewportData={ viewportData }
startDate={ startDate }
/>
</div>
<CustomTimelineBackground
gap={gapSize}
minutesPerGap={minutesPerGapAllowed[minutesPerGapIndex]}
/>
<CustomTimelinePanel
gap={gapSize}
minutesPerGap={minutesPerGapAllowed[minutesPerGapIndex]}
viewportData={viewportData}
startDate={startDate}
/>
</ReactFlow>
</div>
) : null
Expand Down
8 changes: 5 additions & 3 deletions openbas-front/src/components/CustomTimelinePanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -61,16 +61,18 @@ function BackgroundComponent({
dateIndex: Math.round(date.unix() / (minutesPerGap * 3 * 60)),
});
} else {
const date = moment.utc(startDate)
const beginningDate = moment.utc(startDate)
.add(-new Date().getTimezoneOffset() / 60, 'h');
const date = moment.utc(beginningDate)
.add((minutesPerGap * 3 * i) + offset, 'm');
newParsedDates.push({
parsedDate: date.format('MMMM Do, YYYY - h:mmA'),
dateIndex: Math.round(date.unix() / (minutesPerGap * 3 * 60)),
dateIndex: Math.round((date.unix() - beginningDate.unix()) / (minutesPerGap * 3 * 60)),
});
}
}
setParsedDates(newParsedDates);
}, [viewportData, minutesPerGap]);
}, [viewportData, minutesPerGap, startDate]);

return (
<Panel className={classes.panel}>
Expand Down
4 changes: 4 additions & 0 deletions openbas-front/src/static/css/index.css
Original file line number Diff line number Diff line change
Expand Up @@ -155,4 +155,8 @@ input[type="file"] {

.react-flow__controls {
border: 1px solid #b5b7ba;
}

.react-flow__pane.draggable:not(.react-flow__pane.draggable.dragging) {
cursor: none !important;
}

0 comments on commit 6197126

Please sign in to comment.