Skip to content

Commit

Permalink
CSSTUDIO-2728: Add keyboard navigation of entries
Browse files Browse the repository at this point in the history
  • Loading branch information
Max Frederiksen authored and maxfrederiksen-ess committed Nov 1, 2024
1 parent d14a4e3 commit 768ff76
Show file tree
Hide file tree
Showing 3 changed files with 84 additions and 24 deletions.
69 changes: 56 additions & 13 deletions src/beta/components/search/SearchResultList/SearchResultList.jsx
Original file line number Diff line number Diff line change
@@ -1,43 +1,86 @@
import React from "react";
import React, { useEffect } from "react";
import { Divider, Stack, styled } from "@mui/material";
import { getLogEntryGroupId } from "components/Properties";
import { SearchResultGroupItem } from "./SearchResultGroupItem/SearchResultGroupItem";
import { SearchResultSingleItem } from "./SearchResultSingleItem";
import { sortByCreatedDate } from "components/log/sort";
import { useKeyPress } from "hooks/useKeyPress";
import { updateCurrentLogEntry, useCurrentLogEntry } from "features/currentLogEntryReducer";
import { useDispatch } from "react-redux";
import useBetaNavigate from "hooks/useBetaNavigate";

export const SearchResultList = styled(({logs, dateDescending, selectedId, onRowClick, className}) => {
export const SearchResultList = styled(({ logs, dateDescending, className }) => {
const dispatch = useDispatch();
const navigate = useBetaNavigate();

const currentLogEntry = useCurrentLogEntry();
const currentLogEntryId = Number(currentLogEntry?.id);
const arrowUpPressed = useKeyPress('ArrowUp');
const arrowDownPressed = useKeyPress('ArrowDown');

const removeSubsequentReplies = (logs) => {
const visitedGroups = []
return logs.reduce((res, log) => {
if(log.groupId && visitedGroups.includes(log.groupId)) {
if (log.groupId && visitedGroups.includes(log.groupId)) {
return [...res];
} else {
visitedGroups.push(log.groupId);
return [...res, log];
}
}, []);
}
const logsAndReplies = logs.map(log => ({
...log,
groupId: getLogEntryGroupId(log.properties)
})).toSorted(sortByCreatedDate(dateDescending))

const transformedLogs = removeSubsequentReplies(
logs.map(log => ({
...log,
groupId: getLogEntryGroupId(log.properties)
}))
.toSorted(sortByCreatedDate(dateDescending))
const logsNoReplies = removeSubsequentReplies(
logsAndReplies
);

const navigateToEntry = (log) => {
dispatch(updateCurrentLogEntry(log));
navigate(`/logs/${log.id}`);
}

const keyboardNavigate = (nextEntryId) => {
const nextEntry = logsAndReplies.find(log => log.id === nextEntryId);
if (nextEntry) {
navigateToEntry(nextEntry);
}
}

const setDefaultLogEntry = () => {
if (!currentLogEntryId) {
dispatch(updateCurrentLogEntry(logsNoReplies[0]));
}
}

useEffect(() => {
if (arrowUpPressed) {
setDefaultLogEntry();
keyboardNavigate(currentLogEntryId + 1);
}
}, [arrowUpPressed]);

useEffect(() => {
if (arrowDownPressed) {
setDefaultLogEntry();
keyboardNavigate(currentLogEntryId - 1);
}
}, [arrowDownPressed]);

return (
<Stack
overflow="scroll"
className={`SearchResultList ${className}`}
divider={<Divider flexItem />}
>
{transformedLogs?.map(log => {
if(log.groupId) {
return <SearchResultGroupItem key={log.id} log={log} selectedId={selectedId} onClick={onRowClick} dateDescending={dateDescending} />
{logsNoReplies?.map(log => {
if (log.groupId) {
return <SearchResultGroupItem key={log.id} log={log} selectedId={currentLogEntryId} onClick={navigateToEntry} dateDescending={dateDescending} />
} else {
return <SearchResultSingleItem key={log.id} log={log} selected={`${selectedId}` === `${log.id}`} onClick={onRowClick} />
return <SearchResultSingleItem key={log.id} log={log} selected={`${currentLogEntryId}` === `${log.id}`} onClick={navigateToEntry} />
}
})}
</Stack>
Expand Down
11 changes: 0 additions & 11 deletions src/beta/components/search/SearchResults.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { Alert, Badge, Box, IconButton, LinearProgress, Stack, TablePagination, Typography, styled } from "@mui/material";
import { ologApi, removeEmptyKeys } from "api/ologApi";
import customization from "config/customization";
import { updateCurrentLogEntry, useCurrentLogEntry } from "features/currentLogEntryReducer";
import { updateSearchPageParams, useSearchPageParams } from "features/searchPageParamsReducer";
import { updateSearchParams, useSearchParams } from "features/searchParamsReducer";
import React, { useEffect, useMemo, useState } from "react";
Expand All @@ -14,15 +13,12 @@ import { SearchParamsBadges } from "./SearchParamsBadges";
import { AdvancedSearchDrawer } from "./SearchResultList/AdvancedSearchDrawer";
import { useAdvancedSearch } from "features/advancedSearchReducer";
import { withCacheBust } from "hooks/useSanitizedSearchParams";
import useBetaNavigate from "hooks/useBetaNavigate";

export const SearchResults = styled(({ className }) => {

const dispatch = useDispatch();
const navigate = useBetaNavigate();

const { active: advancedSearchActive, fieldCount: advancedSearchFieldCount } = useAdvancedSearch();
const currentLogEntry = useCurrentLogEntry();
const searchParams = useSearchParams();
const searchPageParams = useSearchPageParams();
const rowsPerPageOptions = customization.defaultRowsPerPageOptions;
Expand Down Expand Up @@ -86,11 +82,6 @@ export const SearchResults = styled(({ className }) => {

const count = searchResults?.hitCount ?? 0;

const onRowClick = (log) => {
dispatch(updateCurrentLogEntry(log));
navigate(`/logs/${log.id}`);
}

const onPageChange = (event, page) => {
setPage(page);
};
Expand Down Expand Up @@ -159,8 +150,6 @@ export const SearchResults = styled(({ className }) => {
? <SearchResultList
logs={searchResults.logs}
dateDescending={searchPageParams?.dateDescending}
selectedId={currentLogEntry?.id}
onRowClick={onRowClick}
/>
: <Box >
<Typography>No records found</Typography>
Expand Down
28 changes: 28 additions & 0 deletions src/hooks/useKeyPress.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { useEffect, useState } from "react";
export const useKeyPress = (targetKey) => {
const [keyPressed, setKeyPressed] = useState(false);

useEffect(() => {
const downHandler = ({ key }) => {
if (key === targetKey) {
setKeyPressed(true);
}
};

const upHandler = ({ key }) => {
if (key === targetKey) {
setKeyPressed(false);
}
};

window.addEventListener('keydown', downHandler);
window.addEventListener('keyup', upHandler);

return () => {
window.removeEventListener('keydown', downHandler);
window.removeEventListener('keyup', upHandler);
};
}, [targetKey]);

return keyPressed;
};

0 comments on commit 768ff76

Please sign in to comment.