CE-551 Add keyboard shortcuts to Record Query screen; fix to not take keyboard commands while keyboard-help screen is up

This commit is contained in:
2023-07-25 14:10:43 -05:00
parent cd7e6b8db1
commit 9c51b3949e
5 changed files with 78 additions and 8 deletions

View File

@ -574,6 +574,7 @@ export default function App()
const [tableMetaData, setTableMetaData] = useState(null); const [tableMetaData, setTableMetaData] = useState(null);
const [tableProcesses, setTableProcesses] = useState(null); const [tableProcesses, setTableProcesses] = useState(null);
const [dotMenuOpen, setDotMenuOpen] = useState(false); const [dotMenuOpen, setDotMenuOpen] = useState(false);
const [keyboardHelpOpen, setKeyboardHelpOpen] = useState(false);
return ( return (
appRoutes && ( appRoutes && (
@ -583,11 +584,13 @@ export default function App()
tableMetaData: tableMetaData, tableMetaData: tableMetaData,
tableProcesses: tableProcesses, tableProcesses: tableProcesses,
dotMenuOpen: dotMenuOpen, dotMenuOpen: dotMenuOpen,
keyboardHelpOpen: keyboardHelpOpen,
setPageHeader: (header: string | JSX.Element) => setPageHeader(header), setPageHeader: (header: string | JSX.Element) => setPageHeader(header),
setAccentColor: (accentColor: string) => setAccentColor(accentColor), setAccentColor: (accentColor: string) => setAccentColor(accentColor),
setTableMetaData: (tableMetaData: QTableMetaData) => setTableMetaData(tableMetaData), setTableMetaData: (tableMetaData: QTableMetaData) => setTableMetaData(tableMetaData),
setTableProcesses: (tableProcesses: QProcessMetaData[]) => setTableProcesses(tableProcesses), setTableProcesses: (tableProcesses: QProcessMetaData[]) => setTableProcesses(tableProcesses),
setDotMenuOpen: (dotMenuOpent: boolean) => setDotMenuOpen(dotMenuOpent), setDotMenuOpen: (dotMenuOpent: boolean) => setDotMenuOpen(dotMenuOpent),
setKeyboardHelpOpen: (keyboardHelpOpen: boolean) => setKeyboardHelpOpen(keyboardHelpOpen),
pathToLabelMap: pathToLabelMap, pathToLabelMap: pathToLabelMap,
branding: branding branding: branding
}}> }}>

View File

@ -67,9 +67,8 @@ const CommandMenu = ({metaData}: Props) =>
const navigate = useNavigate(); const navigate = useNavigate();
const pathParts = location.pathname.replace(/\/+$/, "").split("/"); const pathParts = location.pathname.replace(/\/+$/, "").split("/");
const {accentColor, tableMetaData, dotMenuOpen, setDotMenuOpen, setTableMetaData, tableProcesses} = useContext(QContext); const {accentColor, tableMetaData, dotMenuOpen, setDotMenuOpen, keyboardHelpOpen, setKeyboardHelpOpen, setTableMetaData, tableProcesses} = useContext(QContext);
const [keyboardHelpOpen, setKeyboardHelpOpen] = useState(false)
const classes = useStyles(); const classes = useStyles();
function evalueKeyPress(e: KeyboardEvent) function evalueKeyPress(e: KeyboardEvent)
@ -351,6 +350,14 @@ const CommandMenu = ({metaData}: Props) =>
<Grid item xs={6} className={classes.item}><span className={classes.keyboardKey}>?</span>Open Keyboard Shortcuts Help</Grid> <Grid item xs={6} className={classes.item}><span className={classes.keyboardKey}>?</span>Open Keyboard Shortcuts Help</Grid>
</Grid> </Grid>
<Typography variant="h6" pt={3}>Table Query</Typography>
<Grid container columnSpacing={5} rowSpacing={1}>
<Grid item xs={6} className={classes.item}><span className={classes.keyboardKey}>n</span>Create a New Record</Grid>
<Grid item xs={6} className={classes.item}><span className={classes.keyboardKey}>r</span>Refresh the Query</Grid>
<Grid item xs={6} className={classes.item}><span className={classes.keyboardKey}>c</span>Open the Columns Panel</Grid>
<Grid item xs={6} className={classes.item}><span className={classes.keyboardKey}>f</span>Open the Filter Panel</Grid>
</Grid>
<Typography variant="h6" pt={3}>Record View</Typography> <Typography variant="h6" pt={3}>Record View</Typography>
<Grid container columnSpacing={5} rowSpacing={1}> <Grid container columnSpacing={5} rowSpacing={1}>
<Grid item xs={6} className={classes.item}><span className={classes.keyboardKey}>n</span>Create a New Record</Grid> <Grid item xs={6} className={classes.item}><span className={classes.keyboardKey}>n</span>Create a New Record</Grid>

View File

@ -37,6 +37,9 @@ interface QContext
dotMenuOpen: boolean; dotMenuOpen: boolean;
setDotMenuOpen?: (dotMenuOpen: boolean) => void; setDotMenuOpen?: (dotMenuOpen: boolean) => void;
keyboardHelpOpen: boolean;
setKeyboardHelpOpen?: (keyboardHelpOpen: boolean) => void;
tableMetaData?: QTableMetaData; tableMetaData?: QTableMetaData;
setTableMetaData?: (tableMetaData: QTableMetaData) => void; setTableMetaData?: (tableMetaData: QTableMetaData) => void;
@ -54,6 +57,7 @@ const defaultState = {
pageHeader: "", pageHeader: "",
accentColor: "#0062FF", accentColor: "#0062FF",
dotMenuOpen: false, dotMenuOpen: false,
keyboardHelpOpen: false,
pathToLabelMap: {}, pathToLabelMap: {},
}; };

View File

@ -51,7 +51,7 @@ import MenuItem from "@mui/material/MenuItem";
import Modal from "@mui/material/Modal"; import Modal from "@mui/material/Modal";
import TextField from "@mui/material/TextField"; import TextField from "@mui/material/TextField";
import Tooltip from "@mui/material/Tooltip"; import Tooltip from "@mui/material/Tooltip";
import {DataGridPro, GridCallbackDetails, GridColDef, GridColumnMenuContainer, GridColumnMenuProps, GridColumnOrderChangeParams, GridColumnPinningMenuItems, GridColumnsMenuItem, GridColumnVisibilityModel, GridDensity, GridEventListener, GridExportMenuItemProps, GridFilterMenuItem, GridFilterModel, GridPinnedColumns, gridPreferencePanelStateSelector, GridRowId, GridRowParams, GridRowsProp, GridSelectionModel, GridSortItem, GridSortModel, GridState, GridToolbarColumnsButton, GridToolbarContainer, GridToolbarDensitySelector, GridToolbarExportContainer, GridToolbarFilterButton, HideGridColMenuItem, MuiEvent, SortGridMenuItems, useGridApiContext, useGridApiEventHandler, useGridSelector} from "@mui/x-data-grid-pro"; import {DataGridPro, GridCallbackDetails, GridColDef, GridColumnMenuContainer, GridColumnMenuProps, GridColumnOrderChangeParams, GridColumnPinningMenuItems, GridColumnsMenuItem, GridColumnVisibilityModel, GridDensity, GridEventListener, GridExportMenuItemProps, GridFilterMenuItem, GridFilterModel, GridPinnedColumns, gridPreferencePanelStateSelector, GridRowId, GridRowParams, GridRowsProp, GridSelectionModel, GridSortItem, GridSortModel, GridState, GridToolbarColumnsButton, GridToolbarContainer, GridToolbarDensitySelector, GridToolbarExportContainer, GridToolbarFilterButton, HideGridColMenuItem, MuiEvent, SortGridMenuItems, useGridApiContext, useGridApiEventHandler, useGridSelector, useGridApiRef, GridPreferencePanelsValue} from "@mui/x-data-grid-pro";
import {GridRowModel} from "@mui/x-data-grid/models/gridRows"; import {GridRowModel} from "@mui/x-data-grid/models/gridRows";
import FormData from "form-data"; import FormData from "form-data";
import React, {forwardRef, useContext, useEffect, useReducer, useRef, useState} from "react"; import React, {forwardRef, useContext, useEffect, useReducer, useRef, useState} from "react";
@ -252,12 +252,65 @@ function RecordQuery({table, launchProcess}: Props): JSX.Element
const [queryErrors, setQueryErrors] = useState({} as any); const [queryErrors, setQueryErrors] = useState({} as any);
const [receivedQueryErrorTimestamp, setReceivedQueryErrorTimestamp] = useState(new Date()); const [receivedQueryErrorTimestamp, setReceivedQueryErrorTimestamp] = useState(new Date());
const {setPageHeader} = useContext(QContext); const {setPageHeader, dotMenuOpen, keyboardHelpOpen} = useContext(QContext);
const [, forceUpdate] = useReducer((x) => x + 1, 0); const [, forceUpdate] = useReducer((x) => x + 1, 0);
const openActionsMenu = (event: any) => setActionsMenu(event.currentTarget); const openActionsMenu = (event: any) => setActionsMenu(event.currentTarget);
const closeActionsMenu = () => setActionsMenu(null); const closeActionsMenu = () => setActionsMenu(null);
const gridApiRef = useGridApiRef();
///////////////////////
// Keyboard handling //
///////////////////////
useEffect(() =>
{
if(tableMetaData == null)
{
(async() =>
{
const tableMetaData = await qController.loadTableMetaData(tableName);
setTableMetaData(tableMetaData);
})();
}
const down = (e: KeyboardEvent) =>
{
const type = (e.target as any).type;
const validType = (type !== "text" && type !== "textarea" && type !== "input" && type !== "search");
if(validType && !dotMenuOpen && !keyboardHelpOpen && !activeModalProcess)
{
if (! e.metaKey && e.key === "n" && table.capabilities.has(Capability.TABLE_INSERT) && table.insertPermission)
{
e.preventDefault()
navigate(`${metaData?.getTablePathByName(tableName)}/create`);
}
else if (! e.metaKey && e.key === "r")
{
e.preventDefault()
updateTable();
}
else if (! e.metaKey && e.key === "c")
{
e.preventDefault()
gridApiRef.current.showPreferences(GridPreferencePanelsValue.columns)
}
else if (! e.metaKey && e.key === "f")
{
e.preventDefault()
gridApiRef.current.showFilterPanel()
}
}
}
document.addEventListener("keydown", down)
return () =>
{
document.removeEventListener("keydown", down)
}
}, [dotMenuOpen, keyboardHelpOpen, metaData, activeModalProcess])
///////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////
// monitor location changes - if our url looks like a process, then open that process. // // monitor location changes - if our url looks like a process, then open that process. //
///////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////
@ -1934,6 +1987,7 @@ function RecordQuery({table, launchProcess}: Props): JSX.Element
<Card> <Card>
<Box height="100%"> <Box height="100%">
<DataGridPro <DataGridPro
apiRef={gridApiRef}
components={{ components={{
Toolbar: CustomToolbar, Toolbar: CustomToolbar,
Pagination: CustomPagination, Pagination: CustomPagination,

View File

@ -116,7 +116,7 @@ function RecordView({table, launchProcess}: Props): JSX.Element
const openActionsMenu = (event: any) => setActionsMenu(event.currentTarget); const openActionsMenu = (event: any) => setActionsMenu(event.currentTarget);
const closeActionsMenu = () => setActionsMenu(null); const closeActionsMenu = () => setActionsMenu(null);
const {accentColor, setPageHeader, tableMetaData, setTableMetaData, tableProcesses, setTableProcesses, dotMenuOpen} = useContext(QContext); const {accentColor, setPageHeader, tableMetaData, setTableMetaData, tableProcesses, setTableProcesses, dotMenuOpen, keyboardHelpOpen} = useContext(QContext);
if (localStorage.getItem(tableVariantLocalStorageKey)) if (localStorage.getItem(tableVariantLocalStorageKey))
{ {
@ -138,7 +138,9 @@ function RecordView({table, launchProcess}: Props): JSX.Element
setShowAudit(false); setShowAudit(false);
}; };
// Toggle the menu when ⌘K is pressed ///////////////////////
// Keyboard handling //
///////////////////////
useEffect(() => useEffect(() =>
{ {
if(tableMetaData == null) if(tableMetaData == null)
@ -155,7 +157,7 @@ function RecordView({table, launchProcess}: Props): JSX.Element
const type = (e.target as any).type; const type = (e.target as any).type;
const validType = (type !== "text" && type !== "textarea" && type !== "input" && type !== "search"); const validType = (type !== "text" && type !== "textarea" && type !== "input" && type !== "search");
if(validType && !dotMenuOpen && !showAudit && !showEditChildForm) if(validType && !dotMenuOpen && !keyboardHelpOpen && !showAudit && !showEditChildForm)
{ {
if (! e.metaKey && e.key === "n" && table.capabilities.has(Capability.TABLE_INSERT) && table.insertPermission) if (! e.metaKey && e.key === "n" && table.capabilities.has(Capability.TABLE_INSERT) && table.insertPermission)
{ {
@ -190,7 +192,7 @@ function RecordView({table, launchProcess}: Props): JSX.Element
{ {
document.removeEventListener("keydown", down) document.removeEventListener("keydown", down)
} }
}, [dotMenuOpen, showEditChildForm, showAudit, metaData]) }, [dotMenuOpen, keyboardHelpOpen, showEditChildForm, showAudit, metaData])
const gotoCreate = () => const gotoCreate = () =>
{ {