diff --git a/src/App.tsx b/src/App.tsx index 59ee713..c9995f6 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -574,6 +574,7 @@ export default function App() const [tableMetaData, setTableMetaData] = useState(null); const [tableProcesses, setTableProcesses] = useState(null); const [dotMenuOpen, setDotMenuOpen] = useState(false); + const [keyboardHelpOpen, setKeyboardHelpOpen] = useState(false); return ( appRoutes && ( @@ -583,11 +584,13 @@ export default function App() tableMetaData: tableMetaData, tableProcesses: tableProcesses, dotMenuOpen: dotMenuOpen, + keyboardHelpOpen: keyboardHelpOpen, setPageHeader: (header: string | JSX.Element) => setPageHeader(header), setAccentColor: (accentColor: string) => setAccentColor(accentColor), setTableMetaData: (tableMetaData: QTableMetaData) => setTableMetaData(tableMetaData), setTableProcesses: (tableProcesses: QProcessMetaData[]) => setTableProcesses(tableProcesses), setDotMenuOpen: (dotMenuOpent: boolean) => setDotMenuOpen(dotMenuOpent), + setKeyboardHelpOpen: (keyboardHelpOpen: boolean) => setKeyboardHelpOpen(keyboardHelpOpen), pathToLabelMap: pathToLabelMap, branding: branding }}> diff --git a/src/CommandMenu.tsx b/src/CommandMenu.tsx index 6d672f2..f368813 100644 --- a/src/CommandMenu.tsx +++ b/src/CommandMenu.tsx @@ -67,9 +67,8 @@ const CommandMenu = ({metaData}: Props) => const navigate = useNavigate(); 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(); function evalueKeyPress(e: KeyboardEvent) @@ -351,6 +350,14 @@ const CommandMenu = ({metaData}: Props) => ?Open Keyboard Shortcuts Help + Table Query + + nCreate a New Record + rRefresh the Query + cOpen the Columns Panel + fOpen the Filter Panel + + Record View nCreate a New Record diff --git a/src/QContext.tsx b/src/QContext.tsx index 2cd7ca5..b13c8e5 100644 --- a/src/QContext.tsx +++ b/src/QContext.tsx @@ -37,6 +37,9 @@ interface QContext dotMenuOpen: boolean; setDotMenuOpen?: (dotMenuOpen: boolean) => void; + keyboardHelpOpen: boolean; + setKeyboardHelpOpen?: (keyboardHelpOpen: boolean) => void; + tableMetaData?: QTableMetaData; setTableMetaData?: (tableMetaData: QTableMetaData) => void; @@ -54,6 +57,7 @@ const defaultState = { pageHeader: "", accentColor: "#0062FF", dotMenuOpen: false, + keyboardHelpOpen: false, pathToLabelMap: {}, }; diff --git a/src/qqq/pages/records/query/RecordQuery.tsx b/src/qqq/pages/records/query/RecordQuery.tsx index 0a121f8..9ebef6d 100644 --- a/src/qqq/pages/records/query/RecordQuery.tsx +++ b/src/qqq/pages/records/query/RecordQuery.tsx @@ -51,7 +51,7 @@ import MenuItem from "@mui/material/MenuItem"; import Modal from "@mui/material/Modal"; import TextField from "@mui/material/TextField"; 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 FormData from "form-data"; 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 [receivedQueryErrorTimestamp, setReceivedQueryErrorTimestamp] = useState(new Date()); - const {setPageHeader} = useContext(QContext); + const {setPageHeader, dotMenuOpen, keyboardHelpOpen} = useContext(QContext); const [, forceUpdate] = useReducer((x) => x + 1, 0); const openActionsMenu = (event: any) => setActionsMenu(event.currentTarget); 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. // ///////////////////////////////////////////////////////////////////////////////////////// @@ -1934,6 +1987,7 @@ function RecordQuery({table, launchProcess}: Props): JSX.Element setActionsMenu(event.currentTarget); 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)) { @@ -138,7 +138,9 @@ function RecordView({table, launchProcess}: Props): JSX.Element setShowAudit(false); }; - // Toggle the menu when ⌘K is pressed + /////////////////////// + // Keyboard handling // + /////////////////////// useEffect(() => { if(tableMetaData == null) @@ -155,7 +157,7 @@ function RecordView({table, launchProcess}: Props): JSX.Element const type = (e.target as any).type; 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) { @@ -190,7 +192,7 @@ function RecordView({table, launchProcess}: Props): JSX.Element { document.removeEventListener("keydown", down) } - }, [dotMenuOpen, showEditChildForm, showAudit, metaData]) + }, [dotMenuOpen, keyboardHelpOpen, showEditChildForm, showAudit, metaData]) const gotoCreate = () => {