mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 01:38:56 -04:00
[Terminal Output] fixed an issue with the positioning of the playhead and markers. as w… (#141550)
* fixed an issue with the positioning of the playhead and markers. as well as fixed refetch logic for output events * fix for skip to end, and also rendering race condition * smoothed out the slide animation when showing tty player * fix to search highlight regression * null check fix * jest test fix Co-authored-by: Karl Godard <karlgodard@elastic.co>
This commit is contained in:
parent
2e91c672f0
commit
e89ec58e9d
9 changed files with 67 additions and 56 deletions
|
@ -15,19 +15,18 @@ export const useStyles = () => {
|
|||
const cached = useMemo(() => {
|
||||
const descriptionList: CSSObject = {
|
||||
padding: `${euiTheme.size.base} ${euiTheme.size.s} `,
|
||||
alignItems: 'flex-start',
|
||||
};
|
||||
|
||||
const tabListTitle = {
|
||||
width: '40%',
|
||||
display: 'flex',
|
||||
alignItems: 'baseline',
|
||||
marginTop: '0px',
|
||||
};
|
||||
|
||||
const tabListDescription = {
|
||||
width: '60%',
|
||||
display: 'flex',
|
||||
alignItems: 'baseline',
|
||||
marginTop: '0px',
|
||||
};
|
||||
|
||||
|
|
|
@ -81,49 +81,49 @@ export const useIOLines = (pages: ProcessEventsPage[] | undefined) => {
|
|||
return { lines: processedLines, processStartMarkers: processedMarkers };
|
||||
}
|
||||
|
||||
const pagesToProcess = pages.slice(cursor);
|
||||
const events = pages.reduce(
|
||||
(previous, current) => previous.concat(current.events || []),
|
||||
[] as ProcessEvent[]
|
||||
);
|
||||
const eventsToProcess = events.slice(cursor);
|
||||
const newMarkers: ProcessStartMarker[] = [];
|
||||
let newLines: IOLine[] = [];
|
||||
|
||||
newLines = pagesToProcess.reduce((previous, current) => {
|
||||
if (current.events) {
|
||||
current.events.forEach((event) => {
|
||||
const { process } = event;
|
||||
if (process?.io?.text !== undefined && process.entity_id !== undefined) {
|
||||
const splitLines = process.io.text.split(TTY_LINE_SPLITTER_REGEX);
|
||||
const combinedLines = [splitLines[0]];
|
||||
const previousProcessId =
|
||||
previous[previous.length - 1]?.event.process?.entity_id ||
|
||||
processedLines[processedLines.length - 1]?.event.process?.entity_id;
|
||||
eventsToProcess.forEach((event, index) => {
|
||||
const { process } = event;
|
||||
if (process?.io?.text !== undefined && process.entity_id !== undefined) {
|
||||
const previousProcessId =
|
||||
newLines[newLines.length - 1]?.event?.process?.entity_id ||
|
||||
processedLines[processedLines.length - 1]?.event.process?.entity_id;
|
||||
|
||||
if (previousProcessId !== process.entity_id) {
|
||||
const processLineInfo: ProcessStartMarker = {
|
||||
line: processedLines.length + previous.length,
|
||||
event,
|
||||
};
|
||||
newMarkers.push(processLineInfo);
|
||||
}
|
||||
if (previousProcessId !== process.entity_id) {
|
||||
const processLineInfo: ProcessStartMarker = {
|
||||
line: processedLines.length + newLines.length,
|
||||
event,
|
||||
};
|
||||
newMarkers.push(processLineInfo);
|
||||
}
|
||||
|
||||
// delimiters e.g \r\n or cursor movements are merged with their line text
|
||||
// we start on an odd number so that cursor movements happen at the start of each line
|
||||
// this is needed for the search to work accurately
|
||||
for (let i = 1; i < splitLines.length - 1; i = i + 2) {
|
||||
combinedLines.push(splitLines[i] + splitLines[i + 1]);
|
||||
}
|
||||
const splitLines = process.io.text.split(TTY_LINE_SPLITTER_REGEX);
|
||||
const combinedLines = [splitLines[0]];
|
||||
|
||||
const data: IOLine[] = combinedLines.map((line) => {
|
||||
return {
|
||||
event, // pointer to the event so it's easy to look up other details for the line
|
||||
value: line,
|
||||
};
|
||||
});
|
||||
// delimiters e.g \r\n or cursor movements are merged with their line text
|
||||
// we start on an odd number so that cursor movements happen at the start of each line
|
||||
// this is needed for the search to work accurately
|
||||
for (let i = 1; i < splitLines.length - 1; i = i + 2) {
|
||||
combinedLines.push(splitLines[i] + splitLines[i + 1]);
|
||||
}
|
||||
|
||||
previous = previous.concat(data);
|
||||
}
|
||||
const data: IOLine[] = combinedLines.map((line) => {
|
||||
return {
|
||||
event, // pointer to the event so it's easy to look up other details for the line
|
||||
value: line,
|
||||
};
|
||||
});
|
||||
|
||||
newLines = newLines.concat(data);
|
||||
}
|
||||
return previous;
|
||||
}, newLines);
|
||||
});
|
||||
|
||||
const lines = processedLines.concat(newLines);
|
||||
const processStartMarkers = processedMarkers.concat(newMarkers);
|
||||
|
@ -136,8 +136,10 @@ export const useIOLines = (pages: ProcessEventsPage[] | undefined) => {
|
|||
setProcessedMarkers(processStartMarkers);
|
||||
}
|
||||
|
||||
if (pages.length > cursor) {
|
||||
setCursor(pages.length);
|
||||
const newCursor = cursor + eventsToProcess.length;
|
||||
|
||||
if (newCursor > cursor) {
|
||||
setCursor(newCursor);
|
||||
}
|
||||
|
||||
return {
|
||||
|
@ -279,13 +281,14 @@ export const useXtermPlayer = ({
|
|||
useEffect(() => {
|
||||
if (isPlaying) {
|
||||
const timer = setTimeout(() => {
|
||||
if (currentLine < lines.length - 1) {
|
||||
setCurrentLine(Math.min(lines.length - 1, currentLine + TTY_LINES_PER_FRAME));
|
||||
} else {
|
||||
setIsPlaying(false);
|
||||
}
|
||||
|
||||
render(currentLine, false);
|
||||
|
||||
if (currentLine === lines.length - 1) {
|
||||
setIsPlaying(false);
|
||||
} else {
|
||||
const nextLine = Math.min(lines.length - 1, currentLine + TTY_LINES_PER_FRAME);
|
||||
setCurrentLine(nextLine);
|
||||
}
|
||||
}, playSpeed);
|
||||
|
||||
return () => {
|
||||
|
|
|
@ -47,7 +47,8 @@ export const TTYPlayer = ({
|
|||
const ref = useRef<HTMLDivElement>(null);
|
||||
const scrollRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
const { data, fetchNextPage, hasNextPage, isFetching } = useFetchIOEvents(sessionEntityId);
|
||||
const { data, fetchNextPage, hasNextPage, isFetching, refetch } =
|
||||
useFetchIOEvents(sessionEntityId);
|
||||
const { lines, processStartMarkers } = useIOLines(data?.pages);
|
||||
const [fontSize, setFontSize] = useState(DEFAULT_TTY_FONT_SIZE);
|
||||
const [isPlaying, setIsPlaying] = useState(false);
|
||||
|
@ -67,6 +68,13 @@ export const TTYPlayer = ({
|
|||
const currentProcessEvent = lines[Math.min(lines.length - 1, currentLine)]?.event;
|
||||
const tty = currentProcessEvent?.process?.tty;
|
||||
|
||||
useEffect(() => {
|
||||
if (show) {
|
||||
// refetch the most recent page when tty player is loaded
|
||||
refetch({ refetchPage: (_page, index, allPages) => allPages.length - 1 === index });
|
||||
}
|
||||
}, [refetch, show]);
|
||||
|
||||
useEffect(() => {
|
||||
if (
|
||||
autoSeekToEntityId &&
|
||||
|
|
|
@ -20,7 +20,7 @@ export const useStyles = (tty?: Teletype, show?: boolean) => {
|
|||
position: 'absolute',
|
||||
top: 0,
|
||||
opacity: show ? 1 : 0,
|
||||
transition: 'opacity .3s',
|
||||
transition: 'opacity .2s',
|
||||
pointerEvents: show ? 'auto' : 'none',
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
|
@ -38,7 +38,7 @@ export const useStyles = (tty?: Teletype, show?: boolean) => {
|
|||
};
|
||||
|
||||
const header: CSSObject = {
|
||||
display: show ? 'block' : 'none',
|
||||
visibility: show ? 'visible' : 'hidden',
|
||||
backgroundColor: `${euiVars.euiFormBackgroundDisabledColor}`,
|
||||
padding: `${size.m} ${size.base}`,
|
||||
};
|
||||
|
|
|
@ -97,7 +97,7 @@ describe('TTYPlayerControls component', () => {
|
|||
it('clicking on end button triggers onSeekLine', async () => {
|
||||
renderResult = mockedContext.render(<TTYPlayerControls {...props} />);
|
||||
renderResult.queryByTestId('sessionView:TTYPlayerControlsEnd')?.click();
|
||||
expect(props.onSeekLine).toHaveBeenCalledWith(10);
|
||||
expect(props.onSeekLine).toHaveBeenCalledWith(9);
|
||||
});
|
||||
|
||||
it('render output markers', async () => {
|
||||
|
|
|
@ -75,7 +75,7 @@ export const TTYPlayerControls = ({
|
|||
}, [onSeekLine]);
|
||||
|
||||
const seekToEnd = useCallback(() => {
|
||||
onSeekLine(linesLength);
|
||||
onSeekLine(linesLength - 1);
|
||||
}, [linesLength, onSeekLine]);
|
||||
|
||||
const seekToPrevProcess = useCallback(() => {
|
||||
|
|
|
@ -32,7 +32,10 @@ export const TTYPlayerControlsMarkers = ({
|
|||
onChange,
|
||||
onSeekLine,
|
||||
}: Props) => {
|
||||
const progress = useMemo(() => (currentLine / linesLength) * 100, [currentLine, linesLength]);
|
||||
const progress = useMemo(
|
||||
() => (currentLine / (linesLength - 1)) * 100,
|
||||
[currentLine, linesLength]
|
||||
);
|
||||
|
||||
const styles = useStyles(progress);
|
||||
|
||||
|
@ -90,7 +93,7 @@ export const TTYPlayerControlsMarkers = ({
|
|||
// markers positions are absolute, setting higher z-index on the selected one in case there
|
||||
// are severals next to each other
|
||||
const markerWrapperPositioning = {
|
||||
left: `${(line / linesLength) * 100}%`,
|
||||
left: `${(line / (linesLength - 1)) * 100}%`,
|
||||
zIndex: selected ? 3 : 2,
|
||||
};
|
||||
|
||||
|
|
|
@ -85,7 +85,7 @@ export const useStyles = (progress: number) => {
|
|||
"input[type='range']::-moz-range-thumb": customThumb,
|
||||
'.euiRangeHighlight__progress': {
|
||||
backgroundColor: euiVars.euiColorVis0_behindText,
|
||||
width: progress + '%',
|
||||
width: progress + '%!important',
|
||||
borderBottomRightRadius: 0,
|
||||
borderTopRightRadius: 0,
|
||||
},
|
||||
|
|
|
@ -43,6 +43,7 @@ export const getTTYQueryPredicates = async (
|
|||
{ term: { [EVENT_ACTION]: 'fork' } },
|
||||
{ term: { [EVENT_ACTION]: 'exec' } },
|
||||
{ term: { [EVENT_ACTION]: 'end' } },
|
||||
{ term: { [EVENT_ACTION]: 'text_output' } },
|
||||
],
|
||||
must: [{ term: { [ENTRY_SESSION_ENTITY_ID_PROPERTY]: sessionEntityId } }],
|
||||
},
|
||||
|
@ -56,12 +57,9 @@ export const getTTYQueryPredicates = async (
|
|||
|
||||
if (lastEventHits.length > 0) {
|
||||
const lastEvent: ProcessEvent = lastEventHits[0]._source as ProcessEvent;
|
||||
const sessionEnded = lastEvent.event?.action === EventAction.end && lastEvent['@timestamp'];
|
||||
const lastEventTime = lastEvent['@timestamp'];
|
||||
const rangeEnd =
|
||||
sessionEnded && lastEventTime
|
||||
? parse(lastEventTime)?.add(30, 'second').toISOString()
|
||||
: new Date().toISOString();
|
||||
(lastEventTime && parse(lastEventTime)?.toISOString()) || new Date().toISOString();
|
||||
const range = [lastEvent?.process?.entry_leader?.start, rangeEnd];
|
||||
const tty = lastEvent?.process?.entry_leader?.tty;
|
||||
const hostId = lastEvent?.host?.id;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue