/* * QQQ - Low-code Application Framework for Engineers. * Copyright (C) 2021-2023. Kingsrook, LLC * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States * contact@kingsrook.com * https://github.com/Kingsrook/ * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ import {QFieldMetaData} from "@kingsrook/qqq-frontend-core/lib/model/metaData/QFieldMetaData"; import {QInstance} from "@kingsrook/qqq-frontend-core/lib/model/metaData/QInstance"; import {QTableMetaData} from "@kingsrook/qqq-frontend-core/lib/model/metaData/QTableMetaData"; import {QTableVariant} from "@kingsrook/qqq-frontend-core/lib/model/metaData/QTableVariant"; import {QCriteriaOperator} from "@kingsrook/qqq-frontend-core/lib/model/query/QCriteriaOperator"; import {QFilterCriteria} from "@kingsrook/qqq-frontend-core/lib/model/query/QFilterCriteria"; import {QQueryFilter} from "@kingsrook/qqq-frontend-core/lib/model/query/QQueryFilter"; import Box from "@mui/material/Box"; import Button from "@mui/material/Button"; import Dialog from "@mui/material/Dialog"; import DialogActions from "@mui/material/DialogActions"; import DialogContent from "@mui/material/DialogContent"; import DialogTitle from "@mui/material/DialogTitle"; import Grid from "@mui/material/Grid"; import Icon from "@mui/material/Icon"; import TextField from "@mui/material/TextField"; import React, {useState} from "react"; import {useNavigate} from "react-router-dom"; import {QCancelButton} from "qqq/components/buttons/DefaultButtons"; import MDButton from "qqq/components/legacy/MDButton"; import Client from "qqq/utils/qqq/Client"; interface Props { isOpen: boolean; metaData: QInstance; tableMetaData: QTableMetaData; tableVariant?: QTableVariant; closeHandler: () => void; mayClose: boolean; subHeader?: JSX.Element; } GotoRecordDialog.defaultProps = { mayClose: true }; const qController = Client.getInstance(); function hasGotoFieldNames(tableMetaData: QTableMetaData): boolean { const mdbMetaData = tableMetaData?.supplementalTableMetaData?.get("materialDashboard"); if(mdbMetaData && mdbMetaData.gotoFieldNames) { return (true); } return (false); } function GotoRecordDialog(props: Props): JSX.Element { const fields: QFieldMetaData[] = [] let pkey = props?.tableMetaData?.fields.get(props?.tableMetaData?.primaryKeyField); let addedPkey = false; const mdbMetaData = props?.tableMetaData?.supplementalTableMetaData?.get("materialDashboard"); if(mdbMetaData) { if(mdbMetaData.gotoFieldNames) { for(let i = 0; i { const rs = {} as {[field: string]: string}; fields.forEach((field) => rs[field.name] = ""); return (rs); } const [error, setError] = useState(""); const [values, setValues] = useState(makeInitialValues()); const navigate = useNavigate(); const handleChange = (fieldName: string, newValue: string) => { values[fieldName] = newValue; setValues(JSON.parse(JSON.stringify(values))); } const close = () => { setError(""); setValues(makeInitialValues()); props.closeHandler(); } const keyPressed = (e: React.KeyboardEvent) => { // @ts-ignore const targetId: string = e.target?.id; if(e.key == "Esc") { if(props.mayClose) { close(); } } else if(e.key == "Enter" && targetId?.startsWith("gotoInput-")) { const index = targetId?.replaceAll("gotoInput-", ""); document.getElementById("gotoButton-" + index).click(); } } const closeRequested = () => { if(props.mayClose) { close(); } } const goClicked = async (fieldName: string) => { setError(""); const filter = new QQueryFilter([new QFilterCriteria(fieldName, QCriteriaOperator.EQUALS, [values[fieldName]])], null, "AND", null, 10); try { const queryResult = await qController.query(props.tableMetaData.name, filter, null, props.tableVariant) if (queryResult.length == 0) { setError("Record not found."); setTimeout(() => setError(""), 3000); } else if (queryResult.length == 1) { navigate(`${props.metaData.getTablePathByName(props.tableMetaData.name)}/${encodeURIComponent(queryResult[0].values.get(props.tableMetaData.primaryKeyField))}`); close(); } else { setError("More than 1 record found..."); setTimeout(() => setError(""), 3000); } } catch(e) { // @ts-ignore setError(`Error: ${(e && e.message) ? e.message : e}`); setTimeout(() => setError(""), 6000); } } if(props.tableMetaData) { if (fields.length == 0 && !error) { setError("This table is not configured for this feature.") } } return ( closeRequested} onKeyPress={(e) => keyPressed(e)} fullWidth maxWidth={"sm"}> Go To... {props.subHeader} { fields.map((field, index) => ( {field.label} handleChange(field.name, e.target.value)} value={values[field.name]} sx={{width: "100%"}} onFocus={event => event.target.select()} /> goClicked(field.name)} fullWidth startIcon={double_arrow} disabled={`${values[field.name]}`.length == 0}> Go )) } { error && {error} } { //////////////////////////////////////////////////////////////////////////////////////// // show the cancel button if allowed - else we need a little spacing, so an empty box // //////////////////////////////////////////////////////////////////////////////////////// props.mayClose ? :   } ) } interface GotoRecordButtonProps { metaData: QInstance; tableMetaData: QTableMetaData; tableVariant?: QTableVariant; autoOpen?: boolean; buttonVisible?: boolean; mayClose?: boolean; subHeader?: JSX.Element; } GotoRecordButton.defaultProps = { autoOpen: false, buttonVisible: true, mayClose: true }; export function GotoRecordButton(props: GotoRecordButtonProps): JSX.Element { const [gotoIsOpen, setGotoIsOpen] = useState(props.autoOpen) function openGoto() { setGotoIsOpen(true); } function closeGoto() { setGotoIsOpen(false); } return ( { props.buttonVisible && hasGotoFieldNames(props.tableMetaData) && } ); } export default GotoRecordDialog;