mirror of
https://github.com/Kingsrook/qqq-frontend-material-dashboard.git
synced 2025-07-17 21:00:45 +00:00
Merge branch 'dev' into integration/sprint-25
This commit is contained in:
4448
package-lock.json
generated
4448
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -47,9 +47,9 @@
|
||||
},
|
||||
"scripts": {
|
||||
"build": "react-scripts build",
|
||||
"clean": "rm -rf node_modules package-lock.json",
|
||||
"clean": "rm -rf node_modules package-lock.json lib",
|
||||
"eject": "react-scripts eject",
|
||||
"geff-ham": "rm -rf node_modules/ && rm -rf package-lock.json && rm -rf lib/ && npm install",
|
||||
"clean-and-install": "rm -rf node_modules/ && rm -rf package-lock.json && rm -rf lib/ && npm install",
|
||||
"npm-install": "npm install",
|
||||
"prepublishOnly": "tsc -p ./ --outDir lib/",
|
||||
"start": "BROWSER=none react-scripts --max-http-header-size=65535 start",
|
||||
|
@ -26,9 +26,8 @@ import {QTableMetaData} from "@kingsrook/qqq-frontend-core/lib/model/metaData/QT
|
||||
import {QTableSection} from "@kingsrook/qqq-frontend-core/lib/model/metaData/QTableSection";
|
||||
import {QPossibleValue} from "@kingsrook/qqq-frontend-core/lib/model/QPossibleValue";
|
||||
import {QRecord} from "@kingsrook/qqq-frontend-core/lib/model/QRecord";
|
||||
import {Alert} from "@mui/material";
|
||||
import {Alert, Box} from "@mui/material";
|
||||
import Avatar from "@mui/material/Avatar";
|
||||
import Box from "@mui/material/Box";
|
||||
import Card from "@mui/material/Card";
|
||||
import Grid from "@mui/material/Grid";
|
||||
import Icon from "@mui/material/Icon";
|
||||
@ -80,6 +79,7 @@ function EntityForm(props: Props): JSX.Element
|
||||
const [nonT1Sections, setNonT1Sections] = useState([] as QTableSection[]);
|
||||
|
||||
const [alertContent, setAlertContent] = useState("");
|
||||
const [warningContent, setWarningContent] = useState("");
|
||||
|
||||
const [asyncLoadInited, setAsyncLoadInited] = useState(false);
|
||||
const [formValues, setFormValues] = useState({} as { [key: string]: string });
|
||||
@ -424,7 +424,16 @@ function EntityForm(props: Props): JSX.Element
|
||||
{
|
||||
console.log("Caught:");
|
||||
console.log(error);
|
||||
setAlertContent(error.message);
|
||||
|
||||
if(error.message.toLowerCase().startsWith("warning"))
|
||||
{
|
||||
const path = `${location.pathname.replace(/\/edit$/, "")}?updateSuccess=true&warning=${encodeURIComponent(error.message)}`;
|
||||
navigate(path);
|
||||
}
|
||||
else
|
||||
{
|
||||
setAlertContent(error.message);
|
||||
}
|
||||
});
|
||||
}
|
||||
else
|
||||
@ -445,7 +454,15 @@ function EntityForm(props: Props): JSX.Element
|
||||
})
|
||||
.catch((error) =>
|
||||
{
|
||||
setAlertContent(error.message);
|
||||
if(error.message.toLowerCase().startsWith("warning"))
|
||||
{
|
||||
const path = `${location.pathname.replace(/create$/, record.values.get(tableMetaData.primaryKeyField))}?createSuccess=true&warning=${encodeURIComponent(error.message)}`;
|
||||
navigate(path);
|
||||
}
|
||||
else
|
||||
{
|
||||
setAlertContent(error.message);
|
||||
}
|
||||
});
|
||||
}
|
||||
})();
|
||||
@ -485,6 +502,11 @@ function EntityForm(props: Props): JSX.Element
|
||||
<Alert severity="error">{alertContent}</Alert>
|
||||
</Box>
|
||||
) : ("")}
|
||||
{warningContent ? (
|
||||
<Box mb={3}>
|
||||
<Alert severity="warning">{warningContent}</Alert>
|
||||
</Box>
|
||||
) : ("")}
|
||||
</Grid>
|
||||
</Grid>
|
||||
<Grid container spacing={3}>
|
||||
|
@ -29,8 +29,7 @@ import {QRecord} from "@kingsrook/qqq-frontend-core/lib/model/QRecord";
|
||||
import {QFilterCriteria} from "@kingsrook/qqq-frontend-core/lib/model/query/QFilterCriteria";
|
||||
import {QQueryFilter} from "@kingsrook/qqq-frontend-core/lib/model/query/QQueryFilter";
|
||||
import {QueryJoin} from "@kingsrook/qqq-frontend-core/lib/model/query/QueryJoin";
|
||||
import {Alert, Collapse, TablePagination} from "@mui/material";
|
||||
import Box from "@mui/material/Box";
|
||||
import {Alert, Box, Collapse, TablePagination} from "@mui/material";
|
||||
import Button from "@mui/material/Button";
|
||||
import Card from "@mui/material/Card";
|
||||
import Dialog from "@mui/material/Dialog";
|
||||
@ -53,7 +52,6 @@ import {DataGridPro, GridCallbackDetails, GridColDef, GridColumnMenuContainer, G
|
||||
import {GridColumnsPanelProps} from "@mui/x-data-grid/components/panel/GridColumnsPanel";
|
||||
import {gridColumnDefinitionsSelector, gridColumnVisibilityModelSelector} from "@mui/x-data-grid/hooks/features/columns/gridColumnsSelector";
|
||||
import {GridRowModel} from "@mui/x-data-grid/models/gridRows";
|
||||
import {finance} from "faker";
|
||||
import FormData from "form-data";
|
||||
import React, {forwardRef, useContext, useEffect, useReducer, useRef, useState} from "react";
|
||||
import {useLocation, useNavigate, useSearchParams} from "react-router-dom";
|
||||
|
@ -26,9 +26,8 @@ import {QProcessMetaData} from "@kingsrook/qqq-frontend-core/lib/model/metaData/
|
||||
import {QTableMetaData} from "@kingsrook/qqq-frontend-core/lib/model/metaData/QTableMetaData";
|
||||
import {QTableSection} from "@kingsrook/qqq-frontend-core/lib/model/metaData/QTableSection";
|
||||
import {QRecord} from "@kingsrook/qqq-frontend-core/lib/model/QRecord";
|
||||
import {Alert, Typography} from "@mui/material";
|
||||
import {Alert, Box, Typography} from "@mui/material";
|
||||
import Avatar from "@mui/material/Avatar";
|
||||
import Box from "@mui/material/Box";
|
||||
import Button from "@mui/material/Button";
|
||||
import Card from "@mui/material/Card";
|
||||
import Dialog from "@mui/material/Dialog";
|
||||
@ -43,7 +42,7 @@ import ListItemIcon from "@mui/material/ListItemIcon";
|
||||
import Menu from "@mui/material/Menu";
|
||||
import MenuItem from "@mui/material/MenuItem";
|
||||
import Modal from "@mui/material/Modal";
|
||||
import React, {useContext, useEffect, useReducer, useState} from "react";
|
||||
import React, {useContext, useEffect, useState} from "react";
|
||||
import {useLocation, useNavigate, useParams, useSearchParams} from "react-router-dom";
|
||||
import QContext from "QContext";
|
||||
import AuditBody from "qqq/components/audits/AuditBody";
|
||||
@ -86,6 +85,7 @@ function RecordView({table, launchProcess}: Props): JSX.Element
|
||||
|
||||
const [asyncLoadInited, setAsyncLoadInited] = useState(false);
|
||||
const [sectionFieldElements, setSectionFieldElements] = useState(null as Map<string, JSX.Element[]>);
|
||||
const [adornmentFieldsMap, setAdornmentFieldsMap] = useState(new Map<string, boolean>);
|
||||
const [deleteConfirmationOpen, setDeleteConfirmationOpen] = useState(false);
|
||||
const [tableMetaData, setTableMetaData] = useState(null);
|
||||
const [metaData, setMetaData] = useState(null as QInstance);
|
||||
@ -99,10 +99,11 @@ function RecordView({table, launchProcess}: Props): JSX.Element
|
||||
const [actionsMenu, setActionsMenu] = useState(null);
|
||||
const [notFoundMessage, setNotFoundMessage] = useState(null);
|
||||
const [successMessage, setSuccessMessage] = useState(null as string);
|
||||
const [warningMessage, setWarningMessage] = useState(null as string);
|
||||
const [searchParams] = useSearchParams();
|
||||
const {setPageHeader} = useContext(QContext);
|
||||
const [activeModalProcess, setActiveModalProcess] = useState(null as QProcessMetaData);
|
||||
const [, forceUpdate] = useReducer((x) => x + 1, 0);
|
||||
const [reloadCounter, setReloadCounter] = useState(0);
|
||||
|
||||
const [launchingProcess, setLaunchingProcess] = useState(launchProcess);
|
||||
const [showEditChildForm, setShowEditChildForm] = useState(null as any);
|
||||
@ -368,8 +369,8 @@ function RecordView({table, launchProcess}: Props): JSX.Element
|
||||
<Box key={section.name} display="flex" flexDirection="column" py={1} pr={2}>
|
||||
{
|
||||
section.fieldNames.map((fieldName: string) => (
|
||||
<Box key={fieldName} flexDirection="row" pr={2}>
|
||||
<Typography variant="button" textTransform="none" fontWeight="bold" pr={1} color="rgb(52, 71, 103)">
|
||||
<Box display="flex" key={fieldName} flexDirection="row" pb={2} pr={2}>
|
||||
<Typography sx={{display: "flex"}} variant="button" textTransform="none" fontWeight="bold" pr={1} color="rgb(52, 71, 103)">
|
||||
{tableMetaData.fields.get(fieldName).label}:
|
||||
<div style={{display: "inline-block", width: 0}}> </div>
|
||||
</Typography>
|
||||
@ -426,8 +427,10 @@ function RecordView({table, launchProcess}: Props): JSX.Element
|
||||
{
|
||||
setSuccessMessage(`${tableMetaData.label} successfully ${searchParams.get("createSuccess") ? "created" : "updated"}`);
|
||||
}
|
||||
|
||||
forceUpdate();
|
||||
if (searchParams.get("warning"))
|
||||
{
|
||||
setWarningMessage(searchParams.get("warning"));
|
||||
}
|
||||
})();
|
||||
}
|
||||
|
||||
@ -455,6 +458,13 @@ function RecordView({table, launchProcess}: Props): JSX.Element
|
||||
})();
|
||||
};
|
||||
|
||||
function handleRevealIconClick(fieldName: string)
|
||||
{
|
||||
adornmentFieldsMap.set(fieldName, !adornmentFieldsMap.get(fieldName));
|
||||
setAdornmentFieldsMap(adornmentFieldsMap);
|
||||
setReloadCounter(reloadCounter + 1);
|
||||
}
|
||||
|
||||
function processClicked(process: QProcessMetaData)
|
||||
{
|
||||
openModalProcess(process);
|
||||
@ -646,6 +656,16 @@ function RecordView({table, launchProcess}: Props): JSX.Element
|
||||
</Alert>
|
||||
: ("")
|
||||
}
|
||||
{
|
||||
warningMessage ?
|
||||
<Alert color="warning" sx={{mb: 3}} onClose={() =>
|
||||
{
|
||||
setWarningMessage(null);
|
||||
}}>
|
||||
{warningMessage}
|
||||
</Alert>
|
||||
: ("")
|
||||
}
|
||||
|
||||
<Grid container spacing={3}>
|
||||
<Grid item xs={12} lg={3}>
|
||||
|
@ -384,4 +384,10 @@ input[type="search"]::-webkit-search-results-decoration { display: none; }
|
||||
.dashboardDropdownMenu #timeframe-form label
|
||||
{
|
||||
font-size: 0.875rem;
|
||||
}
|
||||
}
|
||||
|
||||
.MuiGrid-root > .MuiBox-root > .material-icons-round,
|
||||
.MuiBox-root > .MuiBox-root > .material-icons-round
|
||||
{
|
||||
font-size: 2rem !important;
|
||||
}
|
||||
|
@ -25,10 +25,11 @@ import {QFieldType} from "@kingsrook/qqq-frontend-core/lib/model/metaData/QField
|
||||
import {QInstance} from "@kingsrook/qqq-frontend-core/lib/model/metaData/QInstance";
|
||||
import {QRecord} from "@kingsrook/qqq-frontend-core/lib/model/QRecord";
|
||||
import "datejs"; // https://github.com/datejs/Datejs
|
||||
import {Box, Chip, Icon} from "@mui/material";
|
||||
import {Box, Chip, ClickAwayListener, Icon} from "@mui/material";
|
||||
import Button from "@mui/material/Button";
|
||||
import Tooltip from "@mui/material/Tooltip";
|
||||
import parse from "html-react-parser";
|
||||
import React, {Fragment, useState} from "react";
|
||||
import React, {Fragment, useReducer, useState} from "react";
|
||||
import AceEditor from "react-ace";
|
||||
import {Link} from "react-router-dom";
|
||||
import Client from "qqq/utils/qqq/Client";
|
||||
@ -79,6 +80,7 @@ class ValueUtils
|
||||
return ValueUtils.getValueForDisplay(field, rawValue, displayValue, usage);
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** When you have a field and a value (either just a raw value, or a raw and
|
||||
** display value), call this method to get a string Element to display.
|
||||
@ -132,6 +134,11 @@ class ValueUtils
|
||||
}
|
||||
}
|
||||
|
||||
if (field.hasAdornment(AdornmentType.REVEAL))
|
||||
{
|
||||
return (<RevealComponent fieldName={field.name} value={displayValue} usage={usage} />);
|
||||
}
|
||||
|
||||
if (field.hasAdornment(AdornmentType.RENDER_HTML))
|
||||
{
|
||||
return (rawValue ? parse(rawValue) : "");
|
||||
@ -470,6 +477,68 @@ function CodeViewer({name, mode, code}: {name: string; mode: string; code: strin
|
||||
</>);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// little private component here, for rendering an AceEditor with some buttons/controls/state //
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
function RevealComponent({fieldName, value, usage}: {fieldName: string, value: string, usage: string;}): JSX.Element
|
||||
{
|
||||
const [adornmentFieldsMap, setAdornmentFieldsMap] = useState(new Map<string, boolean>);
|
||||
const [, forceUpdate] = useReducer((x) => x + 1, 0);
|
||||
const [tooltipOpen, setToolTipOpen] = useState(false);
|
||||
const [displayValue, setDisplayValue] = useState(value.replace(/./g, "*"));
|
||||
|
||||
const handleTooltipClose = () =>
|
||||
{
|
||||
setToolTipOpen(false);
|
||||
};
|
||||
|
||||
const handleTooltipOpen = () =>
|
||||
{
|
||||
setToolTipOpen(true);
|
||||
};
|
||||
|
||||
const handleRevealIconClick = (fieldName: string) =>
|
||||
{
|
||||
const displayValue = (adornmentFieldsMap.get(fieldName)) ? value.replace(/./g, "*") : value;
|
||||
setDisplayValue(displayValue);
|
||||
adornmentFieldsMap.set(fieldName, !adornmentFieldsMap.get(fieldName));
|
||||
setAdornmentFieldsMap(adornmentFieldsMap);
|
||||
forceUpdate();
|
||||
};
|
||||
|
||||
const copyToClipboard = (value: string) =>
|
||||
{
|
||||
navigator.clipboard.writeText(value);
|
||||
setToolTipOpen(true);
|
||||
};
|
||||
|
||||
return (
|
||||
usage === "view" && adornmentFieldsMap.get(fieldName) === true ? (
|
||||
<Box>
|
||||
<Icon onClick={() => handleRevealIconClick(fieldName)} sx={{cursor: "pointer", fontSize: "15px !important", position: "relative", top: "3px", marginRight: "5px"}}>visibility_on</Icon>
|
||||
{displayValue}
|
||||
<ClickAwayListener onClickAway={handleTooltipClose}>
|
||||
<Tooltip
|
||||
PopperProps={{
|
||||
disablePortal: true,
|
||||
}}
|
||||
onClose={handleTooltipClose}
|
||||
open={tooltipOpen}
|
||||
disableFocusListener
|
||||
disableHoverListener
|
||||
disableTouchListener
|
||||
title="Copied To Clipboard"
|
||||
>
|
||||
<Icon onClick={() => copyToClipboard(value)} sx={{cursor: "pointer", fontSize: "15px !important", position: "relative", top: "3px", marginLeft: "5px"}}>copy</Icon>
|
||||
</Tooltip>
|
||||
</ClickAwayListener>
|
||||
</Box>
|
||||
):(
|
||||
<Box><Icon onClick={() => handleRevealIconClick(fieldName)} sx={{cursor: "pointer", fontSize: "15px !important", position: "relative", top: "3px", marginRight: "5px"}}>visibility_off</Icon>{displayValue}</Box>
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
export default ValueUtils;
|
||||
|
Reference in New Issue
Block a user