diff --git a/package.json b/package.json
index 65b58a2..df1703b 100644
--- a/package.json
+++ b/package.json
@@ -6,7 +6,7 @@
"@auth0/auth0-react": "1.10.2",
"@emotion/react": "11.7.1",
"@emotion/styled": "11.6.0",
- "@kingsrook/qqq-frontend-core": "1.0.66",
+ "@kingsrook/qqq-frontend-core": "1.0.68",
"@mui/icons-material": "5.4.1",
"@mui/material": "5.11.1",
"@mui/styles": "5.11.1",
diff --git a/src/qqq/components/audits/AuditBody.tsx b/src/qqq/components/audits/AuditBody.tsx
index 072f277..f98d540 100644
--- a/src/qqq/components/audits/AuditBody.tsx
+++ b/src/qqq/components/audits/AuditBody.tsx
@@ -108,6 +108,10 @@ function AuditBody({tableMetaData, recordId, record}: Props): JSX.Element
{
return (<>{fieldLabel}: Removed value {(oldValue)}>);
}
+ else if(message)
+ {
+ return (<>{message}>);
+ }
/*
const fieldLabel = {tableMetaData?.fields?.get(fieldName)?.label ?? fieldName};
diff --git a/src/qqq/components/forms/DynamicForm.tsx b/src/qqq/components/forms/DynamicForm.tsx
index 13eafb3..d98ecd2 100644
--- a/src/qqq/components/forms/DynamicForm.tsx
+++ b/src/qqq/components/forms/DynamicForm.tsx
@@ -19,15 +19,20 @@
* along with this program. If not, see .
*/
-import {colors} from "@mui/material";
+import {QFieldMetaData} from "@kingsrook/qqq-frontend-core/lib/model/metaData/QFieldMetaData";
+import {QFieldType} from "@kingsrook/qqq-frontend-core/lib/model/metaData/QFieldType";
+import {QRecord} from "@kingsrook/qqq-frontend-core/lib/model/QRecord";
+import {colors, Icon, InputLabel} from "@mui/material";
import Box from "@mui/material/Box";
import Button from "@mui/material/Button";
import Grid from "@mui/material/Grid";
+import Tooltip from "@mui/material/Tooltip";
import {useFormikContext} from "formik";
import React, {useState} from "react";
import QDynamicFormField from "qqq/components/forms/DynamicFormField";
import DynamicSelect from "qqq/components/forms/DynamicSelect";
import MDTypography from "qqq/components/legacy/MDTypography";
+import ValueUtils from "qqq/utils/qqq/ValueUtils";
interface Props
{
@@ -35,6 +40,7 @@ interface Props
formData: any;
bulkEditMode?: boolean;
bulkEditSwitchChangeHandler?: any;
+ record?: QRecord;
}
function QDynamicForm(props: Props): JSX.Element
@@ -60,6 +66,14 @@ function QDynamicForm(props: Props): JSX.Element
formikProps.setFieldValue(field.name, event.currentTarget.files[0]);
};
+ const removeFile = (fieldName: string) =>
+ {
+ setFileName(null);
+ formikProps.setFieldValue(fieldName, null);
+ props.record?.values.delete(fieldName)
+ props.record?.displayValues.delete(fieldName)
+ };
+
const bulkEditSwitchChanged = (name: string, value: boolean) =>
{
bulkEditSwitchChangeHandler(name, value);
@@ -94,10 +108,23 @@ function QDynamicForm(props: Props): JSX.Element
if (field.type === "file")
{
+ const pseudoField = new QFieldMetaData({name: fieldName, type: QFieldType.BLOB});
return (
+ {field.label}
+ {
+ props.record && props.record.values.get(fieldName) &&
+ Current File:
+
+ {ValueUtils.getDisplayValue(pseudoField, props.record, "view")}
+
+ removeFile(fieldName)}>delete
+
+
+
+ }
);
}
-////////////////////////////////////////////////////////////////////////////////////////////////
-// little private component here, for rendering an AceEditor with some buttons/controls/state //
-////////////////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// little private component here, for rendering "secret-ish" values, that you can click to reveal or copy //
+////////////////////////////////////////////////////////////////////////////////////////////////////////////
function RevealComponent({fieldName, value, usage}: {fieldName: string, value: string, usage: string;}): JSX.Element
{
const [adornmentFieldsMap, setAdornmentFieldsMap] = useState(new Map);
@@ -561,7 +569,7 @@ function RevealComponent({fieldName, value, usage}: {fieldName: string, value: s
):(
- handleRevealIconClick(e, fieldName)} sx={{cursor: "pointer", fontSize: "15px !important", position: "relative", top: "3px", marginRight: "5px"}}>visibility_off{displayValue}
+ handleRevealIconClick(e, fieldName)} sx={{cursor: "pointer", fontSize: "15px !important", position: "relative", top: "3px", marginRight: "5px"}}>visibility_off{displayValue}
)
)
}
@@ -570,5 +578,59 @@ function RevealComponent({fieldName, value, usage}: {fieldName: string, value: s
}
+interface BlobComponentProps
+{
+ field: QFieldMetaData;
+ url: string;
+ filename: string;
+ usage: "view" | "query";
+}
+
+BlobComponent.defaultProps = {
+ usage: "view",
+};
+
+function BlobComponent({field, url, filename, usage}: BlobComponentProps): JSX.Element
+{
+ const download = (event: React.MouseEvent) =>
+ {
+ event.stopPropagation();
+ HtmlUtils.downloadUrlViaIFrame(url);
+ };
+
+ const open = (event: React.MouseEvent) =>
+ {
+ event.stopPropagation();
+ HtmlUtils.openInNewWindow(url, filename);
+ };
+
+ if(!filename || !url)
+ {
+ return ();
+ }
+
+ const tooltipPlacement = usage == "view" ? "bottom" : "right";
+
+ // todo - thumbnails if adorned?
+ // challenge is - must post (for auth header)...
+ return (
+
+ {
+ usage == "view" && filename
+ }
+
+ open(e)}>open_in_new
+
+
+ download(e)}>save_alt
+
+ {
+ usage == "query" && filename
+ }
+
+ );
+}
+
+
export default ValueUtils;